<commit_before>#![crate_name = "uu_pr"]

// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
//

#[cfg(unix)]
extern crate unix_socket;
#[macro_use]
extern crate quick_error;
extern crate chrono;
extern crate getopts;
extern crate uucore;

use std::io::{BufRead, BufReader, stdin, stdout, stderr, Error, Read, Write, Stdout};
use std::vec::Vec;
use chrono::offset::Local;
use chrono::DateTime;
use getopts::{Matches, Options};
use std::fs::{metadata, File};
#[cfg(unix)]
use std::os::unix::fs::FileTypeExt;
use quick_error::ResultExt;

static NAME: &str = "pr";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static LINES_PER_PAGE: usize = 66;
static HEADER_LINES_PER_PAGE: usize = 5;
static TRAILER_LINES_PER_PAGE: usize = 5;
static CONTENT_LINES_PER_PAGE: usize = LINES_PER_PAGE - HEADER_LINES_PER_PAGE - TRAILER_LINES_PER_PAGE;
static NUMBERING_MODE_DEFAULT_SEPARATOR: &str = "\t";
static NUMBERING_MODE_DEFAULT_WIDTH: usize = 5;

struct OutputOptions {
    /// Line numbering mode
    number: Option<NumberingMode>,
    header: String,
    double_spaced: bool,
    line_separator: String,
    last_modified_time: String,
}

impl AsRef<OutputOptions> for OutputOptions {
    fn as_ref(&self) -> &OutputOptions {
        self
    }
}

struct NumberingMode {
    /// Line numbering mode
    width: usize,
    separator: String,
}

impl Default for NumberingMode {
    fn default() -> NumberingMode {
        NumberingMode {
            width: NUMBERING_MODE_DEFAULT_WIDTH,
            separator: NUMBERING_MODE_DEFAULT_SEPARATOR.to_string(),
        }
    }
}

enum InputType {
    Directory,
    File,
    StdIn,
    SymLink,
    #[cfg(unix)]
    BlockDevice,
    #[cfg(unix)]
    CharacterDevice,
    #[cfg(unix)]
    Fifo,
    #[cfg(unix)]
    Socket,
}

quick_error! {
    #[derive(Debug)]
    enum PrError {
        Input(err: Error, path: String) {
            context(path: &'a str, err: Error) -> (err, path.to_owned())
            display("pr: Reading from input {0} gave error", path)
            cause(err)
        }

        UnknownFiletype(path: String) {
            display("pr: {0}: unknown filetype", path)
        }

        EncounteredErrors(msg: String) {
            display("pr: {0} encountered", msg)
        }
        IsDirectory(path: String) {
            display("pr: {0}: Is a directory", path)
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optopt(
        "h",
        "",
        "Use the string header to replace the file name \
     in the header line.",
        "STRING",
    );

    opts.optflag(
        "d",
        "",
        "Produce output that is double spaced. An extra <newline> character is output following every <newline>
           found in the input.",
    );

    opts.optflagopt(
        "n",
        "",
        "Provide width digit line numbering.  The default for width, if not specified, is 5.  The number occupies
           the first width column positions of each text column or each line of -m output.  If char (any nondigit
           character) is given, it is appended to the line number to separate it from whatever follows.  The default
           for char is a <tab>.  Line numbers longer than width columns are truncated.",
        "[char][width]",
    );

    opts.optflag("", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => panic!("Invalid options\n{}", e),
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    let mut files: Vec<String> = matches.free.clone();
    if files.is_empty() {
        //For stdin
        files.push("-".to_owned());
    }

    if matches.opt_present("help") {
        return print_usage(&mut opts, &matches);
    }

    for f in files {
        let header: &String = &matches.opt_str("h").unwrap_or(f.to_string());
        let options: &OutputOptions = &build_options(&matches, header, &f);
        let status: i32 = pr(&f, options);
        if status != 0 {
            return status;
        }
    }
    return 0;
}

fn print_usage(opts: &mut Options, matches: &Matches) -> i32 {
    println!("{} {} -- print files", NAME, VERSION);
    println!();
    println!("Usage: {} [+page] [-column] [-adFfmprt] [[-e] [char] [gap]]
        [-L locale] [-h header] [[-i] [char] [gap]]
        [-l lines] [-o offset] [[-s] [char]] [[-n] [char]
        [width]] [-w width] [-] [file ...].", NAME);
    println!();
    let usage: &str = "The pr utility is a printing and pagination filter
     for text files.  When multiple input files are spec-
     ified, each is read, formatted, and written to stan-
     dard output.  By default, the input is separated
     into 66-line pages, each with

     o   A 5-line header with the page number, date,
         time, and the pathname of the file.

     o   A 5-line trailer consisting of blank lines.

     If standard output is associated with a terminal,
     diagnostic messages are suppressed until the pr
     utility has completed processing.

     When multiple column output is specified, text col-
     umns are of equal width.  By default text columns
     are separated by at least one <blank>.  Input lines
     that do not fit into a text column are truncated.
     Lines are not truncated under single column output.";
    println!("{}", opts.usage(usage));
    if matches.free.is_empty() {
        return 1;
    }
    return 0;
}

fn build_options(matches: &Matches, header: &String, path: &String) -> OutputOptions {
    let numbering_options: Option<NumberingMode> = matches.opt_str("n").map(|i| {
        NumberingMode {
            width: i.parse::<usize>().unwrap_or(NumberingMode::default().width),
            separator: NumberingMode::default().separator,
        }
    }).or_else(|| {
        if matches.opt_present("n") {
            return Some(NumberingMode::default());
        }
        return None;
    });

    let line_separator: String = if matches.opt_present("d") {
        "\n\n".to_string()
    } else {
        "\n".to_string()
    };

    let last_modified_time = if path.eq("-") {
        current_time()
    } else {
        file_last_modified_time(path)
    };

    OutputOptions {
        number: numbering_options,
        header: header.to_string(),
        double_spaced: matches.opt_present("d"),
        line_separator,
        last_modified_time,
    }
}

fn open(path: &str) -> Result<Box<Read>, PrError> {
    match get_input_type(path) {
        Some(InputType::Directory) => Err(PrError::IsDirectory(path.to_string())),
        #[cfg(unix)]
        Some(InputType::Socket) => {
            // TODO Add reading from socket
            Err(PrError::EncounteredErrors("Reading from socket not supported yet".to_string()))
        }
        Some(InputType::StdIn) => {
            let stdin = stdin();
            Ok(Box::new(stdin) as Box<Read>)
        }
        Some(_) => Ok(Box::new(File::open(path).context(path)?) as Box<Read>),
        None => Err(PrError::UnknownFiletype(path.to_string()))
    }
}

fn pr(path: &str, options: &OutputOptions) -> i32 {
    let mut i = 0;
    let mut page: usize = 0;
    let mut buffered_content: Vec<String> = Vec::new();
    match open(path) {
        Ok(reader) => {
            // TODO Replace the loop
            for line in BufReader::new(reader).lines() {
                if i == CONTENT_LINES_PER_PAGE {
                    page = page + 1;
                    i = 0;
                    prepare_page(&mut buffered_content, options, &page);
                }
                match line {
                    Ok(content) => buffered_content.push(content),
                    Err(error) => {
                        writeln!(&mut stderr(), "pr: Unable to read from input type {}\n{}", path, error.to_string());
                        return -1;
                    }
                }
                i = i + 1;
            }

            if i != 0 {
                page = page + 1;
                prepare_page(&mut buffered_content, options, &page);
            }
        }
        Err(error) => {
            writeln!(&mut stderr(), "{}", error);
            return -1;
        }
    }
    return 0;
}

fn print_page(header_content: &Vec<String>, lines: &Vec<String>, options: &OutputOptions, page: &usize) {
    let trailer_content: Vec<String> = trailer_content();
    assert_eq!(lines.len() <= CONTENT_LINES_PER_PAGE, true, "Only {} lines of content allowed in a pr output page", CONTENT_LINES_PER_PAGE);
    assert_eq!(header_content.len(), HEADER_LINES_PER_PAGE, "Only {} lines of content allowed in a pr header", HEADER_LINES_PER_PAGE);
    assert_eq!(trailer_content.len(), TRAILER_LINES_PER_PAGE, "Only {} lines of content allowed in a pr trailer", TRAILER_LINES_PER_PAGE);
    let out: &mut Stdout = &mut stdout();
    let line_separator = options.as_ref().line_separator.as_bytes();

    out.lock();
    for x in header_content {
        out.write(x.as_bytes());
        out.write(line_separator);
    }

    let width: usize = options.as_ref()
        .number.as_ref()
        .map(|i| i.width)
        .unwrap_or(0);
    let separator: String = options.as_ref()
        .number.as_ref()
        .map(|i| i.separator.to_string())
        .unwrap_or(NumberingMode::default().separator);

    let prev_lines = CONTENT_LINES_PER_PAGE * (page - 1);
    let mut i = 1;
    for x in lines {
        if options.number.is_none() {
            out.write(x.as_bytes());
        } else {
            let fmtd_line_number: String = get_fmtd_line_number(&width, prev_lines + i, &separator);
            out.write(format!("{}{}", fmtd_line_number, x).as_bytes());
        }
        out.write(line_separator);
        i = i + 1;
    }
    for x in trailer_content {
        out.write(x.as_bytes());
        out.write(line_separator);
    }
    out.flush();
}

fn get_fmtd_line_number(width: &usize, line_number: usize, separator: &String) -> String {
    let line_str = line_number.to_string();
    if line_str.len() >= *width {
        format!("{:>width$}{}", &line_str[line_str.len() - *width..], separator, width = width)
    } else {
        format!("{:>width$}{}", line_str, separator, width = width)
    }
}

fn prepare_page(buffered_content: &mut Vec<String>, options: &OutputOptions, page: &usize) {
    let header: Vec<String> = header_content(&options, &page);
    print_page(&header, buffered_content, &options, &page);
    buffered_content.clear();
}

fn header_content(options: &OutputOptions, page: &usize) -> Vec<String> {
    let first_line: String = format!("{} {} Page {}", options.last_modified_time, options.header, page);
    vec!["".to_string(), "".to_string(), first_line, "".to_string(), "".to_string()]
}

fn file_last_modified_time(path: &str) -> String {
    let file_metadata = metadata(path);
    return file_metadata.map(|i| {
        return i.modified().map(|x| {
            let datetime: DateTime<Local> = x.into();
            datetime.format("%b %d %H:%M %Y").to_string()
        }).unwrap_or(String::new());
    }).unwrap_or(String::new());
}

fn current_time() -> String {
    let datetime: DateTime<Local> = Local::now();
    datetime.format("%b %d %H:%M %Y").to_string()
}

fn trailer_content() -> Vec<String> {
    vec!["".to_string(), "".to_string(), "".to_string(), "".to_string(), "".to_string()]
}

fn get_input_type(path: &str) -> Option<InputType> {
    if path == "-" {
        return Some(InputType::StdIn);
    }

    metadata(path).map(|i| {
        match i.file_type() {
            #[cfg(unix)]
            ft if ft.is_block_device() =>
                {
                    Some(InputType::BlockDevice)
                }
            #[cfg(unix)]
            ft if ft.is_char_device() =>
                {
                    Some(InputType::CharacterDevice)
                }
            #[cfg(unix)]
            ft if ft.is_fifo() =>
                {
                    Some(InputType::Fifo)
                }
            #[cfg(unix)]
            ft if ft.is_socket() =>
                {
                    Some(InputType::Socket)
                }
            ft if ft.is_dir() => Some(InputType::Directory),
            ft if ft.is_file() => Some(InputType::File),
            ft if ft.is_symlink() => Some(InputType::SymLink),
            _ => None
        }
    }).unwrap_or(None)
}
<commit_msg>pr: refactor option flags into constants<commit_after>#![crate_name = "uu_pr"]

// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
//

#[cfg(unix)]
extern crate unix_socket;
#[macro_use]
extern crate quick_error;
extern crate chrono;
extern crate getopts;
extern crate uucore;

use std::io::{BufRead, BufReader, stdin, stdout, stderr, Error, Read, Write, Stdout};
use std::vec::Vec;
use chrono::offset::Local;
use chrono::DateTime;
use getopts::{Matches, Options};
use std::fs::{metadata, File};
#[cfg(unix)]
use std::os::unix::fs::FileTypeExt;
use quick_error::ResultExt;

static NAME: &str = "pr";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static LINES_PER_PAGE: usize = 66;
static HEADER_LINES_PER_PAGE: usize = 5;
static TRAILER_LINES_PER_PAGE: usize = 5;
static CONTENT_LINES_PER_PAGE: usize = LINES_PER_PAGE - HEADER_LINES_PER_PAGE - TRAILER_LINES_PER_PAGE;
static NUMBERING_MODE_DEFAULT_SEPARATOR: &str = "\t";
static NUMBERING_MODE_DEFAULT_WIDTH: usize = 5;
static STRING_HEADER_OPTION: &str = "h";
static NUMBERING_MODE_OPTION: &str = "n";
static FILE_STDIN: &str = "-";

struct OutputOptions {
    /// Line numbering mode
    number: Option<NumberingMode>,
    header: String,
    double_spaced: bool,
    line_separator: String,
    last_modified_time: String,
}

impl AsRef<OutputOptions> for OutputOptions {
    fn as_ref(&self) -> &OutputOptions {
        self
    }
}

struct NumberingMode {
    /// Line numbering mode
    width: usize,
    separator: String,
}

impl Default for NumberingMode {
    fn default() -> NumberingMode {
        NumberingMode {
            width: NUMBERING_MODE_DEFAULT_WIDTH,
            separator: NUMBERING_MODE_DEFAULT_SEPARATOR.to_string(),
        }
    }
}

enum InputType {
    Directory,
    File,
    StdIn,
    SymLink,
    #[cfg(unix)]
    BlockDevice,
    #[cfg(unix)]
    CharacterDevice,
    #[cfg(unix)]
    Fifo,
    #[cfg(unix)]
    Socket,
}

quick_error! {
    #[derive(Debug)]
    enum PrError {
        Input(err: Error, path: String) {
            context(path: &'a str, err: Error) -> (err, path.to_owned())
            display("pr: Reading from input {0} gave error", path)
            cause(err)
        }

        UnknownFiletype(path: String) {
            display("pr: {0}: unknown filetype", path)
        }

        EncounteredErrors(msg: String) {
            display("pr: {0} encountered", msg)
        }
        IsDirectory(path: String) {
            display("pr: {0}: Is a directory", path)
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optopt(
        STRING_HEADER_OPTION,
        "",
        "Use the string header to replace the file name \
     in the header line.",
        "STRING",
    );

    opts.optflag(
        "d",
        "",
        "Produce output that is double spaced. An extra <newline> character is output following every <newline>
           found in the input.",
    );

    opts.optflagopt(
        NUMBERING_MODE_OPTION,
        "",
        "Provide width digit line numbering.  The default for width, if not specified, is 5.  The number occupies
           the first width column positions of each text column or each line of -m output.  If char (any nondigit
           character) is given, it is appended to the line number to separate it from whatever follows.  The default
           for char is a <tab>.  Line numbers longer than width columns are truncated.",
        "[char][width]",
    );

    opts.optflag("", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => panic!("Invalid options\n{}", e),
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    let mut files: Vec<String> = matches.free.clone();
    if files.is_empty() {
        //For stdin
        files.push(FILE_STDIN.to_owned());
    }

    if matches.opt_present("help") {
        return print_usage(&mut opts, &matches);
    }

    for f in files {
        let header: &String = &matches.opt_str(STRING_HEADER_OPTION).unwrap_or(f.to_string());
        let options: &OutputOptions = &build_options(&matches, header, &f);
        let status: i32 = pr(&f, options);
        if status != 0 {
            return status;
        }
    }
    return 0;
}

fn print_usage(opts: &mut Options, matches: &Matches) -> i32 {
    println!("{} {} -- print files", NAME, VERSION);
    println!();
    println!("Usage: {} [+page] [-column] [-adFfmprt] [[-e] [char] [gap]]
        [-L locale] [-h header] [[-i] [char] [gap]]
        [-l lines] [-o offset] [[-s] [char]] [[-n] [char]
        [width]] [-w width] [-] [file ...].", NAME);
    println!();
    let usage: &str = "The pr utility is a printing and pagination filter
     for text files.  When multiple input files are spec-
     ified, each is read, formatted, and written to stan-
     dard output.  By default, the input is separated
     into 66-line pages, each with

     o   A 5-line header with the page number, date,
         time, and the pathname of the file.

     o   A 5-line trailer consisting of blank lines.

     If standard output is associated with a terminal,
     diagnostic messages are suppressed until the pr
     utility has completed processing.

     When multiple column output is specified, text col-
     umns are of equal width.  By default text columns
     are separated by at least one <blank>.  Input lines
     that do not fit into a text column are truncated.
     Lines are not truncated under single column output.";
    println!("{}", opts.usage(usage));
    if matches.free.is_empty() {
        return 1;
    }
    return 0;
}

fn build_options(matches: &Matches, header: &String, path: &String) -> OutputOptions {
    let numbering_options: Option<NumberingMode> = matches.opt_str(NUMBERING_MODE_OPTION).map(|i| {
        NumberingMode {
            width: i.parse::<usize>().unwrap_or(NumberingMode::default().width),
            separator: NumberingMode::default().separator,
        }
    }).or_else(|| {
        if matches.opt_present(NUMBERING_MODE_OPTION) {
            return Some(NumberingMode::default());
        }
        return None;
    });

    let line_separator: String = if matches.opt_present("d") {
        "\n\n".to_string()
    } else {
        "\n".to_string()
    };

    let last_modified_time = if path.eq(FILE_STDIN) {
        current_time()
    } else {
        file_last_modified_time(path)
    };

    OutputOptions {
        number: numbering_options,
        header: header.to_string(),
        double_spaced: matches.opt_present("d"),
        line_separator,
        last_modified_time,
    }
}

fn open(path: &str) -> Result<Box<Read>, PrError> {
    match get_input_type(path) {
        Some(InputType::Directory) => Err(PrError::IsDirectory(path.to_string())),
        #[cfg(unix)]
        Some(InputType::Socket) => {
            // TODO Add reading from socket
            Err(PrError::EncounteredErrors("Reading from socket not supported yet".to_string()))
        }
        Some(InputType::StdIn) => {
            let stdin = stdin();
            Ok(Box::new(stdin) as Box<Read>)
        }
        Some(_) => Ok(Box::new(File::open(path).context(path)?) as Box<Read>),
        None => Err(PrError::UnknownFiletype(path.to_string()))
    }
}

fn pr(path: &str, options: &OutputOptions) -> i32 {
    let mut i = 0;
    let mut page: usize = 0;
    let mut buffered_content: Vec<String> = Vec::new();
    match open(path) {
        Ok(reader) => {
            // TODO Replace the loop
            for line in BufReader::new(reader).lines() {
                if i == CONTENT_LINES_PER_PAGE {
                    page = page + 1;
                    i = 0;
                    prepare_page(&mut buffered_content, options, &page);
                }
                match line {
                    Ok(content) => buffered_content.push(content),
                    Err(error) => {
                        writeln!(&mut stderr(), "pr: Unable to read from input type {}\n{}", path, error.to_string());
                        return -1;
                    }
                }
                i = i + 1;
            }

            if i != 0 {
                page = page + 1;
                prepare_page(&mut buffered_content, options, &page);
            }
        }
        Err(error) => {
            writeln!(&mut stderr(), "{}", error);
            return -1;
        }
    }
    return 0;
}

fn print_page(header_content: &Vec<String>, lines: &Vec<String>, options: &OutputOptions, page: &usize) {
    let trailer_content: Vec<String> = trailer_content();
    assert_eq!(lines.len() <= CONTENT_LINES_PER_PAGE, true, "Only {} lines of content allowed in a pr output page", CONTENT_LINES_PER_PAGE);
    assert_eq!(header_content.len(), HEADER_LINES_PER_PAGE, "Only {} lines of content allowed in a pr header", HEADER_LINES_PER_PAGE);
    assert_eq!(trailer_content.len(), TRAILER_LINES_PER_PAGE, "Only {} lines of content allowed in a pr trailer", TRAILER_LINES_PER_PAGE);
    let out: &mut Stdout = &mut stdout();
    let line_separator = options.as_ref().line_separator.as_bytes();

    out.lock();
    for x in header_content {
        out.write(x.as_bytes());
        out.write(line_separator);
    }

    let width: usize = options.as_ref()
        .number.as_ref()
        .map(|i| i.width)
        .unwrap_or(0);
    let separator: String = options.as_ref()
        .number.as_ref()
        .map(|i| i.separator.to_string())
        .unwrap_or(NumberingMode::default().separator);

    let prev_lines = CONTENT_LINES_PER_PAGE * (page - 1);
    let mut i = 1;
    for x in lines {
        if options.number.is_none() {
            out.write(x.as_bytes());
        } else {
            let fmtd_line_number: String = get_fmtd_line_number(&width, prev_lines + i, &separator);
            out.write(format!("{}{}", fmtd_line_number, x).as_bytes());
        }
        out.write(line_separator);
        i = i + 1;
    }
    for x in trailer_content {
        out.write(x.as_bytes());
        out.write(line_separator);
    }
    out.flush();
}

fn get_fmtd_line_number(width: &usize, line_number: usize, separator: &String) -> String {
    let line_str = line_number.to_string();
    if line_str.len() >= *width {
        format!("{:>width$}{}", &line_str[line_str.len() - *width..], separator, width = width)
    } else {
        format!("{:>width$}{}", line_str, separator, width = width)
    }
}

fn prepare_page(buffered_content: &mut Vec<String>, options: &OutputOptions, page: &usize) {
    let header: Vec<String> = header_content(&options, &page);
    print_page(&header, buffered_content, &options, &page);
    buffered_content.clear();
}

fn header_content(options: &OutputOptions, page: &usize) -> Vec<String> {
    let first_line: String = format!("{} {} Page {}", options.last_modified_time, options.header, page);
    vec!["".to_string(), "".to_string(), first_line, "".to_string(), "".to_string()]
}

fn file_last_modified_time(path: &str) -> String {
    let file_metadata = metadata(path);
    return file_metadata.map(|i| {
        return i.modified().map(|x| {
            let datetime: DateTime<Local> = x.into();
            datetime.format("%b %d %H:%M %Y").to_string()
        }).unwrap_or(String::new());
    }).unwrap_or(String::new());
}

fn current_time() -> String {
    let datetime: DateTime<Local> = Local::now();
    datetime.format("%b %d %H:%M %Y").to_string()
}

fn trailer_content() -> Vec<String> {
    vec!["".to_string(), "".to_string(), "".to_string(), "".to_string(), "".to_string()]
}

fn get_input_type(path: &str) -> Option<InputType> {
    if path == FILE_STDIN {
        return Some(InputType::StdIn);
    }

    metadata(path).map(|i| {
        match i.file_type() {
            #[cfg(unix)]
            ft if ft.is_block_device() =>
                {
                    Some(InputType::BlockDevice)
                }
            #[cfg(unix)]
            ft if ft.is_char_device() =>
                {
                    Some(InputType::CharacterDevice)
                }
            #[cfg(unix)]
            ft if ft.is_fifo() =>
                {
                    Some(InputType::Fifo)
                }
            #[cfg(unix)]
            ft if ft.is_socket() =>
                {
                    Some(InputType::Socket)
                }
            ft if ft.is_dir() => Some(InputType::Directory),
            ft if ft.is_file() => Some(InputType::File),
            ft if ft.is_symlink() => Some(InputType::SymLink),
            _ => None
        }
    }).unwrap_or(None)
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! debug {
    ($($arg:expr),*) => {
        #[cfg(debug_assertions)]
        {
            use std::io::*;
            $(writeln!(stderr(), "{} = {:?}", stringify!($arg), $arg).unwrap();)*
        }
    };
}
<commit_msg>Print debug! in color<commit_after>mod debug_core {
    use std::fmt;
    use std::io::{self, Write};

    // ANSI escape codes.
    // These paint succeeding characters in terminal.
    const ESC_YELLOW: &'static str = "\x1B[33m";
    const ESC_GREEN: &'static str = "\x1B[92m";
    const ESC_RESET: &'static str = "\x1B[0m";

    pub fn debug_batch<F>(f: F)
    where
        F: FnOnce(&mut io::StderrLock),
    {
        let err = io::stderr();
        let mut err = err.lock();
        f(&mut err);
        err.flush().unwrap();
    }

    pub fn debug_write<W, T>(err: &mut W, expr: &str, value: &T)
    where
        W: io::Write,
        T: fmt::Debug,
    {
        // The expr is colored by yellow.
        // Rest stdout is colored by green for vis.
        writeln!(
            err,
            "{}{}{} = {:?}{}",
            ESC_YELLOW, expr, ESC_RESET, value, ESC_GREEN
        ).unwrap();
    }
}

#[macro_export]
macro_rules! debug {
    ($($arg:expr),*) => {
        #[cfg(debug_assertions)]
        {
            use self::debug_core::*;
            debug_batch(|err| {
                $(debug_write(err, stringify!($arg), &$arg);)*
            })
        }
    };
}

#[allow(dead_code)]
fn debug_core_false_use_site() {
    // This code will report errors in body of debug!.
    debug!((), ())
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};

use futures::SinkExt;
use futures::channel::mpsc::channel;
use futures::stream::StreamExt;
use tokio::runtime;
use tokio::net::TcpListener;
use tokio_util::codec::Decoder;
use tower_service::Service;

use rustygear::codec::{PacketCodec, Packet};

use crate::queues::{HandleJobStorage, SharedJobStorage};
use crate::worker::{SharedWorkers, Wake};
use crate::service::GearmanService;

pub struct GearmanServer;

const MAX_UNHANDLED_OUT_FRAMES: usize = 1024;

impl GearmanServer {
    async fn run(addr: SocketAddr) {
        let curr_conn_id = Arc::new(AtomicUsize::new(0));
        let queues = SharedJobStorage::new_job_storage();
        let workers = SharedWorkers::new_workers();
        let job_count = Arc::new(AtomicUsize::new(0));
        let senders_by_conn_id = Arc::new(Mutex::new(HashMap::new()));
        let job_waiters = Arc::new(Mutex::new(HashMap::new()));
        let mut listener = TcpListener::bind(&addr).await.unwrap();
        let mut incoming = listener.incoming();
        let mut rt = runtime::Runtime::new().unwrap();
        rt.block_on(async move {
            while let Some(socket_res) = incoming.next().await {
                match socket_res {
                    Ok(sock) => {
                        let conn_id = curr_conn_id.clone().fetch_add(1, Ordering::Relaxed);
                        let pc = PacketCodec{};
                        let (mut sink, mut stream) = pc.framed(sock).split();
                        let (tx, mut rx) = channel::<Packet>(MAX_UNHANDLED_OUT_FRAMES);
                        {
                            let mut senders_by_conn_id = senders_by_conn_id.lock().unwrap();
                            senders_by_conn_id.insert(conn_id, tx.clone());
                        }
                        let mut service = GearmanService::new(
                            conn_id,
                            queues.clone(),
                            workers.clone(),
                            job_count.clone(),
                            senders_by_conn_id.clone(),
                            job_waiters.clone(),
                            //remote.clone(),
                        );
                        // Read stuff, write if needed
                        let reader = async move {
                            while let Some(frame) = stream.next().await {
                                let mut tx = tx.clone();
                                runtime::Handle::current().spawn(async {
                                    if let Ok(response) = service.call(frame.unwrap()).await {
                                        tx.send(response).await;
                                    };
                                });
                            }
                        };

                        let writer = async move {
                            while let Some(packet) = rx.next().await {
                                trace!("Sending {:?}", &packet);
                                sink.send(packet).await;
                            }
                        };
                        runtime::Handle::current().spawn(reader);
                        runtime::Handle::current().spawn(writer);
                    }
                    Err(e) => {
                        error!("{}", e);
                    }
                }
            };
        })
    }
}
<commit_msg>trying service in async block<commit_after>use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};

use futures::SinkExt;
use futures::channel::mpsc::channel;
use futures::stream::StreamExt;
use tokio::runtime;
use tokio::net::TcpListener;
use tokio_util::codec::Decoder;
use tower_service::Service;

use rustygear::codec::{PacketCodec, Packet};

use crate::queues::{HandleJobStorage, SharedJobStorage};
use crate::worker::{SharedWorkers, Wake};
use crate::service::GearmanService;

pub struct GearmanServer;

const MAX_UNHANDLED_OUT_FRAMES: usize = 1024;

impl GearmanServer {
    async fn run(addr: SocketAddr) {
        let curr_conn_id = Arc::new(AtomicUsize::new(0));
        let queues = SharedJobStorage::new_job_storage();
        let workers = SharedWorkers::new_workers();
        let job_count = Arc::new(AtomicUsize::new(0));
        let senders_by_conn_id = Arc::new(Mutex::new(HashMap::new()));
        let job_waiters = Arc::new(Mutex::new(HashMap::new()));
        let mut listener = TcpListener::bind(&addr).await.unwrap();
        let mut incoming = listener.incoming();
        let mut rt = runtime::Runtime::new().unwrap();
        rt.block_on(async move {
            while let Some(socket_res) = incoming.next().await {
                match socket_res {
                    Ok(sock) => {
                        let conn_id = curr_conn_id.clone().fetch_add(1, Ordering::Relaxed);
                        let pc = PacketCodec{};
                        let (mut sink, mut stream) = pc.framed(sock).split();
                        let (tx, mut rx) = channel::<Packet>(MAX_UNHANDLED_OUT_FRAMES);
                        {
                            let mut senders_by_conn_id = senders_by_conn_id.lock().unwrap();
                            senders_by_conn_id.insert(conn_id, tx.clone());
                        }
                        // Read stuff, write if needed
                        let reader = async move {
                            let mut service = GearmanService::new(
                                conn_id,
                                queues.clone(),
                                workers.clone(),
                                job_count.clone(),
                                senders_by_conn_id.clone(),
                                job_waiters.clone(),
                            );
                            while let Some(frame) = stream.next().await {
                                let mut tx = tx.clone();
                                runtime::Handle::current().spawn(async {
                                    async move {
                                        let response = service.call(frame.unwrap()).await;
                                        if let Ok(response) = response {
                                            tx.send(response).await;
                                        }
                                    }
                                });
                            }
                        };

                        let writer = async move {
                            while let Some(packet) = rx.next().await {
                                trace!("Sending {:?}", &packet);
                                sink.send(packet).await;
                            }
                        };
                        runtime::Handle::current().spawn(reader);
                        runtime::Handle::current().spawn(writer);
                    }
                    Err(e) => {
                        error!("{}", e);
                    }
                }
            };
        })
    }
}
<|endoftext|>


<commit_before>//! The HTTP Client that perform query

use std::collections::HashMap;
use std::fmt::Arguments;
use std::io::{self, Write};
use std::net::SocketAddr;

use super::constants;
use super::http;
use super::request::Request;
use super::response::{Response, ResponseBuilder};
use super::results::CabotResult;

/// Perform the http query
#[derive(Default)]
pub struct Client {
    verbose: bool,
    authorities: HashMap<String, SocketAddr>,
}

impl Client {
    /// Construct a new `Client`
    pub fn new() -> Self {
        Client {
            verbose: false,
            authorities: HashMap::new(),
        }
    }

    /// Avoid DNS resolution, force an address to be resolve to a given endpoint.
    /// authority has the format "host:port".
    pub fn add_authority(&mut self, authority: &str, sock_addr: &SocketAddr) {
        self.authorities
            .insert(authority.to_owned(), sock_addr.clone());
    }

    /// Execute the query [Request](../request/struct.Request.html) and
    /// return the associate [Response](../response/struct.Response.html).
    pub fn execute(&self, request: &Request) -> CabotResult<Response> {
        let mut out = CabotLibWrite::new();
        http::http_query(&request, &mut out, &self.authorities, self.verbose, true, true)?;
        out.response()
    }
}

struct CabotLibWrite {
    response_builder: ResponseBuilder,
}

impl CabotLibWrite {
    pub fn new() -> Self {
        CabotLibWrite {
            response_builder: ResponseBuilder::new(),
        }
    }

    pub fn response(&self) -> CabotResult<Response> {
        self.response_builder.build()
    }
}

impl Write for CabotLibWrite {
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        info!("Parsing http response");
        let response: Vec<&[u8]> = constants::SPLIT_HEADERS_RE.splitn(buf, 2).collect();
        let header_len = &response[0].len();
        let headers_str = String::from_utf8_lossy(&response[0]);
        let mut headers: Vec<&str> = constants::SPLIT_HEADER_RE.split(&headers_str).collect();

        let mut builder = ResponseBuilder::new();
        let status_line = headers.remove(0);
        debug!("Adding status line {}", status_line);
        builder = builder.set_status_line(status_line);
        let mut iter_header = headers.iter().peekable();
        let header = iter_header.next();
        if header.is_some() {
            let buf = header.unwrap();
            let mut header = String::with_capacity(buf.len() * 2);
            header.push_str(buf);
            loop {
                {
                    let buf = iter_header.peek();
                    if buf.is_none() {
                        builder = builder.add_header(header.as_str());
                        break;
                    }
                    let buf = buf.unwrap();
                    if buf.starts_with(' ') || buf.starts_with('\t') {
                        debug!("Obsolete line folded header reveived in {}", header);
                        header.push_str(" ");
                        header.push_str(buf.trim_left());
                    } else {
                        debug!("Adding header {}", header);
                        builder = builder.add_header(header.as_str());
                        header.clear();
                        header.push_str(buf);
                    }
                }
                let _ = iter_header.next();
            }
        }
        let body = if (header_len + 4) < buf.len() {
            &buf[(header_len + 4)..buf.len()]
        } else {
            &[]
        };
        // debug!("Adding body {:?}", body);
        builder = builder.set_body(body);
        self.response_builder = builder;
        // debug!("Response Builder - {:?}", self.response_builder);
        Ok(())
    }

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

    // Don't implemented unused method

    fn write(&mut self, _: &[u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::Other, "Not Implemented"))
    }

    fn write_fmt(&mut self, _: Arguments) -> io::Result<()> {
        Err(io::Error::new(io::ErrorKind::Other, "Not Implemented"))
    }
}

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

    #[test]
    fn test_build_http_response_from_string() {
        let response = vec![
            "HTTP/1.1 200 Ok",
            "Content-Type: text/plain",
            "Content-Length: 12",
            "",
            "Hello World!",
        ];
        let response = response.join("\r\n");

        let mut out = CabotLibWrite::new();
        out.write_all(response.as_bytes()).unwrap();
        let response = out.response().unwrap();
        assert_eq!(response.http_version(), "HTTP/1.1");
        assert_eq!(response.status_code(), 200);
        assert_eq!(response.status_line(), "200 Ok");
        let headers: &[&str] = &["Content-Type: text/plain", "Content-Length: 12"];
        assert_eq!(response.headers(), headers);
        assert_eq!(
            response.body_as_string().unwrap(),
            "Hello World!".to_owned()
        );
    }

    #[test]
    fn test_build_http_header_obsolete_line_folding() {
        let response = vec![
            "HTTP/1.1 200 Ok",
            "ows: https://tools.ietf.org/html/rfc7230",
            "  #section-3.2.4",
            "Content-Length: 12",
            "",
            "Hello World!",
        ];
        let response = response.join("\r\n");

        let mut out = CabotLibWrite::new();
        out.write_all(response.as_bytes()).unwrap();
        let response = out.response().unwrap();
        assert_eq!(response.http_version(), "HTTP/1.1");
        assert_eq!(response.status_code(), 200);
        assert_eq!(response.status_line(), "200 Ok");
        let headers: &[&str] = &[
            "ows: https://tools.ietf.org/html/rfc7230 #section-3.2.4",
            "Content-Length: 12",
        ];
        assert_eq!(response.headers(), headers);
        assert_eq!(
            response.body_as_string().unwrap(),
            "Hello World!".to_owned()
        );
    }

    #[test]
    fn test_build_http_header_obsolete_line_folding_tab() {
        let response = vec![
            "HTTP/1.1 200 Ok",
            "ows: https://tools.ietf.org/html/rfc7230",
            "\t#section-3.2.4",
            "Content-Length: 12",
            "",
            "Hello World!",
        ];
        let response = response.join("\r\n");

        let mut out = CabotLibWrite::new();
        out.write_all(response.as_bytes()).unwrap();
        let response = out.response().unwrap();
        assert_eq!(response.http_version(), "HTTP/1.1");
        assert_eq!(response.status_code(), 200);
        assert_eq!(response.status_line(), "200 Ok");
        let headers: &[&str] = &[
            "ows: https://tools.ietf.org/html/rfc7230 #section-3.2.4",
            "Content-Length: 12",
        ];
        assert_eq!(response.headers(), headers);
        assert_eq!(
            response.body_as_string().unwrap(),
            "Hello World!".to_owned()
        );
    }

    #[test]
    fn test_build_http_no_response_body() {
        let response = vec![
            "HTTP/1.1 302 Moved",
            "Location: https://tools.ietf.org/html/rfc7230#section-3.3",
        ];
        let response = response.join("\r\n");

        let mut out = CabotLibWrite::new();
        out.write_all(response.as_bytes()).unwrap();
        let response = out.response().unwrap();
        assert_eq!(response.http_version(), "HTTP/1.1");
        assert_eq!(response.status_code(), 302);
        assert_eq!(response.status_line(), "302 Moved");
        let headers: &[&str] = &["Location: https://tools.ietf.org/html/rfc7230#section-3.3"];
        assert_eq!(response.headers(), headers);
        assert_eq!(response.body_as_string().unwrap(), "");
    }
}
<commit_msg>Expose ip version flags in the Client<commit_after>//! The HTTP Client that perform query

use std::collections::HashMap;
use std::fmt::Arguments;
use std::io::{self, Write};
use std::net::SocketAddr;

use super::constants;
use super::http;
use super::request::Request;
use super::response::{Response, ResponseBuilder};
use super::results::CabotResult;

/// Perform the http query
#[derive(Default)]
pub struct Client {
    verbose: bool,
    ipv4: bool,
    ipv6: bool,
    authorities: HashMap<String, SocketAddr>,
}

impl Client {
    /// Construct a new `Client`
    pub fn new() -> Self {
        Client {
            verbose: false,
            ipv4: true,
            ipv6: true,
            authorities: HashMap::new(),
        }
    }

    /// Set Address Type authorized for DNS resolution.
    /// If every version is set to false, the resolution will failed.
    pub fn set_ip_version(&mut self, ipv4: bool, ipv6: bool) {
        self.ipv4 = ipv4;
        self.ipv6 = ipv6;
    }

    /// Avoid DNS resolution, force an address to be resolve to a given endpoint.
    /// authority has the format "host:port".
    pub fn add_authority(&mut self, authority: &str, sock_addr: &SocketAddr) {
        self.authorities
            .insert(authority.to_owned(), sock_addr.clone());
    }

    /// Execute the query [Request](../request/struct.Request.html) and
    /// return the associate [Response](../response/struct.Response.html).
    pub fn execute(&self, request: &Request) -> CabotResult<Response> {
        let mut out = CabotLibWrite::new();
        http::http_query(
            &request, &mut out, &self.authorities, self.verbose,
            self.ipv4, self.ipv6)?;
        out.response()
    }
}

struct CabotLibWrite {
    response_builder: ResponseBuilder,
}

impl CabotLibWrite {
    pub fn new() -> Self {
        CabotLibWrite {
            response_builder: ResponseBuilder::new(),
        }
    }

    pub fn response(&self) -> CabotResult<Response> {
        self.response_builder.build()
    }
}

impl Write for CabotLibWrite {
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        info!("Parsing http response");
        let response: Vec<&[u8]> = constants::SPLIT_HEADERS_RE.splitn(buf, 2).collect();
        let header_len = &response[0].len();
        let headers_str = String::from_utf8_lossy(&response[0]);
        let mut headers: Vec<&str> = constants::SPLIT_HEADER_RE.split(&headers_str).collect();

        let mut builder = ResponseBuilder::new();
        let status_line = headers.remove(0);
        debug!("Adding status line {}", status_line);
        builder = builder.set_status_line(status_line);
        let mut iter_header = headers.iter().peekable();
        let header = iter_header.next();
        if header.is_some() {
            let buf = header.unwrap();
            let mut header = String::with_capacity(buf.len() * 2);
            header.push_str(buf);
            loop {
                {
                    let buf = iter_header.peek();
                    if buf.is_none() {
                        builder = builder.add_header(header.as_str());
                        break;
                    }
                    let buf = buf.unwrap();
                    if buf.starts_with(' ') || buf.starts_with('\t') {
                        debug!("Obsolete line folded header reveived in {}", header);
                        header.push_str(" ");
                        header.push_str(buf.trim_left());
                    } else {
                        debug!("Adding header {}", header);
                        builder = builder.add_header(header.as_str());
                        header.clear();
                        header.push_str(buf);
                    }
                }
                let _ = iter_header.next();
            }
        }
        let body = if (header_len + 4) < buf.len() {
            &buf[(header_len + 4)..buf.len()]
        } else {
            &[]
        };
        // debug!("Adding body {:?}", body);
        builder = builder.set_body(body);
        self.response_builder = builder;
        // debug!("Response Builder - {:?}", self.response_builder);
        Ok(())
    }

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

    // Don't implemented unused method

    fn write(&mut self, _: &[u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::Other, "Not Implemented"))
    }

    fn write_fmt(&mut self, _: Arguments) -> io::Result<()> {
        Err(io::Error::new(io::ErrorKind::Other, "Not Implemented"))
    }
}

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

    #[test]
    fn test_build_http_response_from_string() {
        let response = vec![
            "HTTP/1.1 200 Ok",
            "Content-Type: text/plain",
            "Content-Length: 12",
            "",
            "Hello World!",
        ];
        let response = response.join("\r\n");

        let mut out = CabotLibWrite::new();
        out.write_all(response.as_bytes()).unwrap();
        let response = out.response().unwrap();
        assert_eq!(response.http_version(), "HTTP/1.1");
        assert_eq!(response.status_code(), 200);
        assert_eq!(response.status_line(), "200 Ok");
        let headers: &[&str] = &["Content-Type: text/plain", "Content-Length: 12"];
        assert_eq!(response.headers(), headers);
        assert_eq!(
            response.body_as_string().unwrap(),
            "Hello World!".to_owned()
        );
    }

    #[test]
    fn test_build_http_header_obsolete_line_folding() {
        let response = vec![
            "HTTP/1.1 200 Ok",
            "ows: https://tools.ietf.org/html/rfc7230",
            "  #section-3.2.4",
            "Content-Length: 12",
            "",
            "Hello World!",
        ];
        let response = response.join("\r\n");

        let mut out = CabotLibWrite::new();
        out.write_all(response.as_bytes()).unwrap();
        let response = out.response().unwrap();
        assert_eq!(response.http_version(), "HTTP/1.1");
        assert_eq!(response.status_code(), 200);
        assert_eq!(response.status_line(), "200 Ok");
        let headers: &[&str] = &[
            "ows: https://tools.ietf.org/html/rfc7230 #section-3.2.4",
            "Content-Length: 12",
        ];
        assert_eq!(response.headers(), headers);
        assert_eq!(
            response.body_as_string().unwrap(),
            "Hello World!".to_owned()
        );
    }

    #[test]
    fn test_build_http_header_obsolete_line_folding_tab() {
        let response = vec![
            "HTTP/1.1 200 Ok",
            "ows: https://tools.ietf.org/html/rfc7230",
            "\t#section-3.2.4",
            "Content-Length: 12",
            "",
            "Hello World!",
        ];
        let response = response.join("\r\n");

        let mut out = CabotLibWrite::new();
        out.write_all(response.as_bytes()).unwrap();
        let response = out.response().unwrap();
        assert_eq!(response.http_version(), "HTTP/1.1");
        assert_eq!(response.status_code(), 200);
        assert_eq!(response.status_line(), "200 Ok");
        let headers: &[&str] = &[
            "ows: https://tools.ietf.org/html/rfc7230 #section-3.2.4",
            "Content-Length: 12",
        ];
        assert_eq!(response.headers(), headers);
        assert_eq!(
            response.body_as_string().unwrap(),
            "Hello World!".to_owned()
        );
    }

    #[test]
    fn test_build_http_no_response_body() {
        let response = vec![
            "HTTP/1.1 302 Moved",
            "Location: https://tools.ietf.org/html/rfc7230#section-3.3",
        ];
        let response = response.join("\r\n");

        let mut out = CabotLibWrite::new();
        out.write_all(response.as_bytes()).unwrap();
        let response = out.response().unwrap();
        assert_eq!(response.http_version(), "HTTP/1.1");
        assert_eq!(response.status_code(), 302);
        assert_eq!(response.status_line(), "302 Moved");
        let headers: &[&str] = &["Location: https://tools.ietf.org/html/rfc7230#section-3.3"];
        assert_eq!(response.headers(), headers);
        assert_eq!(response.body_as_string().unwrap(), "");
    }

}
<|endoftext|>


<commit_before>// mod client

use std::fmt;
use std::cmp;
use std::ops::Deref;
use std::str::FromStr;
use map::*;

/// Client contains information about a TeamSpeak 3 client.
/// # Example
/// ```
/// use sqlib;
///
/// let client = sqlib::Client {
///     clid: 1,
///     cid: 1,
///     client_database_id: 1,
///     client_nickname: "John Doe".to_string(),
///     client_type: 0,
///     connection_connected_time: 0
/// };
///
/// assert!(client.is_client());
///
/// let client_print = format!("{}", client);
///
/// assert_eq!("John Doe".to_string(), client_print);
/// ```
#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Client {
    /// client id
    pub clid: i64,
    /// channel id
    pub cid: i64,
    /// client database id
    pub client_database_id: i64,
    /// client nickname
    pub client_nickname: String,
    /// client type: 0 is client and 1 is query client
    pub client_type: i64,
    /// connection time in milliseconds
    pub connection_connected_time: i64,
}

impl Default for Client {
    fn default() -> Client {
        Client {
            clid: 0,
            cid: 0,
            client_database_id: 0,
            client_nickname: String::new(),
            client_type: 0,
            connection_connected_time: 0,
        }
    }
}

impl Client {
    /// creates a new client from a client id and a nickname
    pub fn new(client_id: i64, nickname: String) -> Client {
        let mut client = Client::default();
        client.clid = client_id;
        client.client_nickname = nickname;
        client
    }
    /// checks if it is a real client
    pub fn is_client(&self) -> bool {
        self.client_type == 0
    }

    pub fn from_map(map: &StringMap) -> Client {
        let mut client = Client::default();
        client.mut_from_map(map);
        client
    }

    pub fn update_from_map(client: Client, map: &StringMap) -> Client {
        let mut client = client.clone();
        client.mut_from_map(map);
        client
    }

    pub fn mut_from_map(&mut self, map: &StringMap) {
        update_from_map(map, "clid", &mut self.clid);
        update_from_map(map, "cid", &mut self.cid);
        update_from_map(map, "client_database_id", &mut self.client_database_id);
        update_from_map(map, "client_nickname", &mut self.client_nickname);
        update_from_map(map, "client_type", &mut self.client_type);
        update_from_map(map,
                        "connection_connected_time",
                        &mut self.connection_connected_time);
    }
}

impl FromStr for Client {
    type Err = super::Error;
    fn from_str(s: &str) -> super::Result<Self> {
        let map = to_map(s);
        Ok(Client::from_map(&map))
    }
}

impl fmt::Display for Client {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{} ({})",
               &self.client_nickname,
               self.connection_connected_time / 1000 / 60) // TODO: generate exact time string
    }
}

impl PartialEq for Client {
    fn eq(&self, other: &Client) -> bool {
        self.clid.eq(&other.clid)
    }
}

impl Eq for Client {}

impl PartialOrd for Client {
    fn partial_cmp(&self, other: &Client) -> Option<cmp::Ordering> {
        self.clid.partial_cmp(&other.clid)
    }
}

impl Ord for Client {
    fn cmp(&self, other: &Client) -> cmp::Ordering {
        self.clid.cmp(&other.clid)
    }
}

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, RustcDecodable, RustcEncodable)]
pub struct ClientList(Vec<Client>);

impl ClientList {
    pub fn vec(&self) -> &Vec<Client> {
        let &ClientList(ref v) = self;
        v
    }

    pub fn get_mut(&mut self) -> &mut Vec<Client> {
        let &mut ClientList(ref mut v) = self;
        v
    }

    pub fn get_vec(self) -> Vec<Client> {
        let ClientList(v) = self;
        v
    }

    pub fn from_maps(maps: &Vec<StringMap>) -> ClientList {
        let mut vec = Vec::new();
        for map in maps.iter() {
            let client = Client::from_map(map);
            vec.push(client);
        }
        ClientList(vec)
    }
}

impl FromStr for ClientList {
    type Err = super::Error;
    fn from_str(s: &str) -> super::Result<Self> {
        let maps = s.split('|').map(to_map).collect();
        Ok(ClientList::from_maps(&maps))
    }
}

impl Deref for ClientList {
    type Target = Vec<Client>;
    fn deref(&self) -> &Vec<Client> {
        self.vec()
    }
}

impl fmt::Display for ClientList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "[ "));
        let mut cls = self.vec().iter();
        if cls.len() > 0 {
            try!(write!(f, "{}", cls.next().unwrap()));
        }
        for client in cls {
            try!(write!(f, ", {}", client));
        }
        write!(f, " ]")
    }
}
<commit_msg>fixing example bug<commit_after>// mod client

use std::fmt;
use std::cmp;
use std::ops::Deref;
use std::str::FromStr;
use map::*;

/// Client contains information about a TeamSpeak 3 client.
/// # Example
/// ```
/// use sqlib;
///
/// let client = sqlib::Client {
///     clid: 1,
///     cid: 1,
///     client_database_id: 1,
///     client_nickname: "John Doe".to_string(),
///     client_type: 0,
///     connection_connected_time: 0
/// };
///
/// assert!(client.is_client());
///
/// let client_print = format!("{}", client);
///
/// assert_eq!("John Doe (0)".to_string(), client_print);
/// ```
#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Client {
    /// client id
    pub clid: i64,
    /// channel id
    pub cid: i64,
    /// client database id
    pub client_database_id: i64,
    /// client nickname
    pub client_nickname: String,
    /// client type: 0 is client and 1 is query client
    pub client_type: i64,
    /// connection time in milliseconds
    pub connection_connected_time: i64,
}

impl Default for Client {
    fn default() -> Client {
        Client {
            clid: 0,
            cid: 0,
            client_database_id: 0,
            client_nickname: String::new(),
            client_type: 0,
            connection_connected_time: 0,
        }
    }
}

impl Client {
    /// creates a new client from a client id and a nickname
    pub fn new(client_id: i64, nickname: String) -> Client {
        let mut client = Client::default();
        client.clid = client_id;
        client.client_nickname = nickname;
        client
    }
    /// checks if it is a real client
    pub fn is_client(&self) -> bool {
        self.client_type == 0
    }

    pub fn from_map(map: &StringMap) -> Client {
        let mut client = Client::default();
        client.mut_from_map(map);
        client
    }

    pub fn update_from_map(client: Client, map: &StringMap) -> Client {
        let mut client = client.clone();
        client.mut_from_map(map);
        client
    }

    pub fn mut_from_map(&mut self, map: &StringMap) {
        update_from_map(map, "clid", &mut self.clid);
        update_from_map(map, "cid", &mut self.cid);
        update_from_map(map, "client_database_id", &mut self.client_database_id);
        update_from_map(map, "client_nickname", &mut self.client_nickname);
        update_from_map(map, "client_type", &mut self.client_type);
        update_from_map(map,
                        "connection_connected_time",
                        &mut self.connection_connected_time);
    }
}

impl FromStr for Client {
    type Err = super::Error;
    fn from_str(s: &str) -> super::Result<Self> {
        let map = to_map(s);
        Ok(Client::from_map(&map))
    }
}

impl fmt::Display for Client {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{} ({})",
               &self.client_nickname,
               self.connection_connected_time / 1000 / 60) // TODO: generate exact time string
    }
}

impl PartialEq for Client {
    fn eq(&self, other: &Client) -> bool {
        self.clid.eq(&other.clid)
    }
}

impl Eq for Client {}

impl PartialOrd for Client {
    fn partial_cmp(&self, other: &Client) -> Option<cmp::Ordering> {
        self.clid.partial_cmp(&other.clid)
    }
}

impl Ord for Client {
    fn cmp(&self, other: &Client) -> cmp::Ordering {
        self.clid.cmp(&other.clid)
    }
}

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, RustcDecodable, RustcEncodable)]
pub struct ClientList(Vec<Client>);

impl ClientList {
    pub fn vec(&self) -> &Vec<Client> {
        let &ClientList(ref v) = self;
        v
    }

    pub fn get_mut(&mut self) -> &mut Vec<Client> {
        let &mut ClientList(ref mut v) = self;
        v
    }

    pub fn get_vec(self) -> Vec<Client> {
        let ClientList(v) = self;
        v
    }

    pub fn from_maps(maps: &Vec<StringMap>) -> ClientList {
        let mut vec = Vec::new();
        for map in maps.iter() {
            let client = Client::from_map(map);
            vec.push(client);
        }
        ClientList(vec)
    }
}

impl FromStr for ClientList {
    type Err = super::Error;
    fn from_str(s: &str) -> super::Result<Self> {
        let maps = s.split('|').map(to_map).collect();
        Ok(ClientList::from_maps(&maps))
    }
}

impl Deref for ClientList {
    type Target = Vec<Client>;
    fn deref(&self) -> &Vec<Client> {
        self.vec()
    }
}

impl fmt::Display for ClientList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "[ "));
        let mut cls = self.vec().iter();
        if cls.len() > 0 {
            try!(write!(f, "{}", cls.next().unwrap()));
        }
        for client in cls {
            try!(write!(f, ", {}", client));
        }
        write!(f, " ]")
    }
}
<|endoftext|>


<commit_before>pub type c_char = i8;
pub type c_long = i64;
pub type c_ulong = u64;

pub type wchar_t = i16;

pub type off_t = c_long;
pub type mode_t = u16;
pub type time_t = i64;
pub type pid_t = usize;
pub type gid_t = usize;
pub type uid_t = usize;

pub type in_addr_t = u32;
pub type in_port_t = u16;

pub type socklen_t = u32;
pub type sa_family_t = u16;

s! {
    pub struct in_addr {
        pub s_addr: in_addr_t,
    }

    pub struct in6_addr {
        pub s6_addr: [u8; 16],
        __align: [u32; 0],
    }

    pub struct sockaddr {
        pub sa_family: sa_family_t,
        pub sa_data: [::c_char; 14],
    }

    pub struct sockaddr_in {
        pub sin_family: sa_family_t,
        pub sin_port: ::in_port_t,
        pub sin_addr: ::in_addr,
        pub sin_zero: [u8; 8],
    }

    pub struct sockaddr_in6 {
        pub sin6_family: sa_family_t,
        pub sin6_port: in_port_t,
        pub sin6_flowinfo: u32,
        pub sin6_addr: ::in6_addr,
        pub sin6_scope_id: u32,
    }
}

pub const STDIN_FILENO: ::c_int = 0;
pub const STDOUT_FILENO: ::c_int = 1;
pub const STDERR_FILENO: ::c_int = 2;

pub const EXIT_FAILURE: ::c_int = 1;
pub const EXIT_SUCCESS: ::c_int = 0;

pub const S_ISUID: ::c_int = 0x800;
pub const S_ISGID: ::c_int = 0x400;
pub const S_ISVTX: ::c_int = 0x200;

pub const S_IFIFO: mode_t = 4096;
pub const S_IFCHR: mode_t = 8192;
pub const S_IFBLK: mode_t = 24576;
pub const S_IFDIR: mode_t = 16384;
pub const S_IFREG: mode_t = 32768;
pub const S_IFLNK: mode_t = 40960;
pub const S_IFSOCK: mode_t = 49152;
pub const S_IFMT: mode_t = 61440;
pub const S_IEXEC: mode_t = 64;
pub const S_IWRITE: mode_t = 128;
pub const S_IREAD: mode_t = 256;
pub const S_IRWXU: mode_t = 448;
pub const S_IXUSR: mode_t = 64;
pub const S_IWUSR: mode_t = 128;
pub const S_IRUSR: mode_t = 256;
pub const S_IRWXG: mode_t = 56;
pub const S_IXGRP: mode_t = 8;
pub const S_IWGRP: mode_t = 16;
pub const S_IRGRP: mode_t = 32;
pub const S_IRWXO: mode_t = 7;
pub const S_IXOTH: mode_t = 1;
pub const S_IWOTH: mode_t = 2;
pub const S_IROTH: mode_t = 4;

extern {
    pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
    pub fn read(fd: ::c_int, buf: *mut ::c_void, count: ::size_t)
                -> ::ssize_t;
    pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t)
                 -> ::ssize_t;
}

#[link(name = "c")]
#[link(name = "m")]
extern {}
<commit_msg>Changed Redox 'mode_t' constants to Hexadecimal.<commit_after>pub type c_char = i8;
pub type c_long = i64;
pub type c_ulong = u64;

pub type wchar_t = i16;

pub type off_t = c_long;
pub type mode_t = u16;
pub type time_t = i64;
pub type pid_t = usize;
pub type gid_t = usize;
pub type uid_t = usize;

pub type in_addr_t = u32;
pub type in_port_t = u16;

pub type socklen_t = u32;
pub type sa_family_t = u16;

s! {
    pub struct in_addr {
        pub s_addr: in_addr_t,
    }

    pub struct in6_addr {
        pub s6_addr: [u8; 16],
        __align: [u32; 0],
    }

    pub struct sockaddr {
        pub sa_family: sa_family_t,
        pub sa_data: [::c_char; 14],
    }

    pub struct sockaddr_in {
        pub sin_family: sa_family_t,
        pub sin_port: ::in_port_t,
        pub sin_addr: ::in_addr,
        pub sin_zero: [u8; 8],
    }

    pub struct sockaddr_in6 {
        pub sin6_family: sa_family_t,
        pub sin6_port: in_port_t,
        pub sin6_flowinfo: u32,
        pub sin6_addr: ::in6_addr,
        pub sin6_scope_id: u32,
    }
}

pub const STDIN_FILENO: ::c_int = 0;
pub const STDOUT_FILENO: ::c_int = 1;
pub const STDERR_FILENO: ::c_int = 2;

pub const EXIT_FAILURE: ::c_int = 1;
pub const EXIT_SUCCESS: ::c_int = 0;

pub const S_ISUID: ::c_int = 0x800;
pub const S_ISGID: ::c_int = 0x400;
pub const S_ISVTX: ::c_int = 0x200;

pub const S_IFIFO: mode_t = 0x1000;
pub const S_IFCHR: mode_t = 0x2000;
pub const S_IFBLK: mode_t = 0x6000;
pub const S_IFDIR: mode_t = 0x4000;
pub const S_IFREG: mode_t = 0x8000;
pub const S_IFLNK: mode_t = 0xA000;
pub const S_IFSOCK: mode_t = 0xC000;
pub const S_IFMT: mode_t = 0xF000;
pub const S_IEXEC: mode_t = 0x40;
pub const S_IWRITE: mode_t = 0x80;
pub const S_IREAD: mode_t = 0x100;
pub const S_IRWXU: mode_t = 0x1C0;
pub const S_IXUSR: mode_t = 0x40;
pub const S_IWUSR: mode_t = 0x80;
pub const S_IRUSR: mode_t = 0x100;
pub const S_IRWXG: mode_t = 0x38;
pub const S_IXGRP: mode_t = 0x8;
pub const S_IWGRP: mode_t = 0x10;
pub const S_IRGRP: mode_t = 0x20;
pub const S_IRWXO: mode_t = 0x7;
pub const S_IXOTH: mode_t = 0x1;
pub const S_IWOTH: mode_t = 0x2;
pub const S_IROTH: mode_t = 0x4;

extern {
    pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
    pub fn read(fd: ::c_int, buf: *mut ::c_void, count: ::size_t)
                -> ::ssize_t;
    pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t)
                 -> ::ssize_t;
}

#[link(name = "c")]
#[link(name = "m")]
extern {}
<|endoftext|>


<commit_before>// Copyright 2015 Joe Neeman.
//
// 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.

use dfa::CompileTarget;
use error::Error;
use nfa::{Nfa, NoLooks};
use runner::forward_backward::ForwardBackwardEngine;
use runner::backtracking::BacktrackingEngine;
use runner::prefix::Prefix;
use runner::program::{Instructions, Program, TableInsts, VmInsts};
use runner::Engine;
use std;
use std::fmt::Debug;

#[derive(Debug)]
pub struct Regex {
    engine: Box<Engine<u8>>,
}

// An engine that doesn't match anything.
#[derive(Clone, Debug)]
struct EmptyEngine;

impl<Ret: Debug> Engine<Ret> for EmptyEngine {
    fn shortest_match(&self, _: &str) -> Option<(usize, usize, Ret)> { None }
    fn clone_box(&self) -> Box<Engine<Ret>> { Box::new(EmptyEngine) }
}

/// An enum listing the different kinds of supported regex engines.
pub enum EngineType {
    /// The backtracking engine will attempt to match the regex starting from offset zero,
    /// then it will try again from offset one, and so on. Although it is quite fast in practice,
    /// it has a poor worst-case behavior. For example, in attempting to match the regex
    /// `"aaaaaaaaaaab"` against the string `"aaaaaaaaaaaaaaaaaaaaaaaaaaa"`, it will look at
    /// each character in the input many times.
    Backtracking,
    /// The forward-backward engine is guaranteed to look at each input character at most twice.
    ForwardBackward,
}

/// An enum listing the different ways for representing the regex program.
pub enum ProgramType {
    /// A `Vm` program represents a regex as a list of instructions. It is a fairly
    /// memory-efficient representation, particularly when the regex contains lots of string
    /// literals.
    Vm,
    /// A `Table` program is the classical table-based implementation of a DFA.
    Table,
}

impl Clone for Regex {
    fn clone(&self) -> Regex {
        Regex {
            engine: self.engine.clone_box(),
        }
    }
}

impl Regex {
    /// Creates a new `Regex` from a regular expression string.
    pub fn new(re: &str) -> Result<Regex, Error> {
        Regex::new_bounded(re, std::usize::MAX)
    }

    /// Creates a new `Regex` from a regular expression string, but only if it doesn't require too
    /// many states.
    pub fn new_bounded(re: &str, max_states: usize) -> Result<Regex, Error> {
        Regex::make_regex(re, max_states, None, None)
    }

    /// Creates a new `Regex` from a regular expression string, with some additional knobs to
    /// tweak.
    ///
    /// - `engine` - specifies the search algorithm to use while executing the regex.
    /// - `program` - specifies the representation of the regex program.
    pub fn new_advanced(re: &str, max_states: usize, engine: EngineType, program: ProgramType)
    -> Result<Regex, Error>
    {
        Regex::make_regex(re, max_states, Some(engine), Some(program))
    }

    fn make_backtracking<I>(nfa: Nfa<u32, NoLooks>, max_states: usize)
    -> Result<BacktrackingEngine<I>, Error> where
    I: Instructions<Ret=u8>,
    Program<I>: CompileTarget<u8> {
        if nfa.has_look_behind() {
            return Err(Error::InvalidEngine("look-behind rules out the backtracking engine"));
        }

        let nfa = try!(nfa.byte_me(max_states));
        let dfa = try!(nfa.determinize_shortest(max_states))
            .optimize_for_shortest_match()
            .map_ret(|(_, bytes)| bytes);
        let (prog, state_map) = dfa.to_program::<Program<I>>();
        let prefix = if dfa.is_anchored() {
            Prefix::Empty
        } else {
            dfa.prefix(&state_map)
        };

        Ok(BacktrackingEngine::new(prog, prefix))
    }

    fn make_forward_backward<FI, BI>(nfa: Nfa<u32, NoLooks>, max_states: usize)
    -> Result<ForwardBackwardEngine<FI, BI>, Error> where
    FI: Instructions<Ret=(usize, u8)>,
    Program<FI>: CompileTarget<(usize, u8)>,
    BI: Instructions<Ret=u8>,
    Program<BI>: CompileTarget<u8>,
    {
        if nfa.is_anchored() {
            return Err(Error::InvalidEngine("anchors rule out the forward-backward engine"));
        }

        let f_nfa = try!(try!(nfa.clone().byte_me(max_states)).anchor_look_behind(max_states));
        let b_nfa = try!(try!(nfa.byte_me(max_states)).reverse(max_states));

        let f_dfa = try!(f_nfa.determinize_shortest(max_states))
            .cut_loop_to_init()
            .optimize_for_shortest_match()
            // Do it again, because optimize might have merged something with the initial state,
            // in which case we can cut more.
            .cut_loop_to_init()
            .optimize_for_shortest_match();
        let b_dfa = try!(b_nfa.determinize_longest(max_states))
            .optimize();
        let b_dfa = b_dfa.map_ret(|(_, bytes)| bytes);

        let (b_prog, b_state_map) = b_dfa.to_program::<Program<BI>>();
        let f_dfa = f_dfa.map_ret(|(look, bytes)| {
            let b_dfa_state = b_dfa.init[look.as_usize()].expect("BUG: back dfa must have this init");
            (b_state_map[b_dfa_state], bytes)
        });
        let (f_prog, f_state_map) = f_dfa.to_program::<Program<FI>>();

        Ok(ForwardBackwardEngine::new(f_prog, f_dfa.pruned_prefix(&f_state_map), b_prog))
    }

    fn make_regex(re: &str, max_states: usize, engine: Option<EngineType>, prog: Option<ProgramType>)
    -> Result<Regex, Error> {
        let nfa = try!(Nfa::from_regex(re));
        let nfa = nfa.remove_looks();

        if nfa.is_empty() {
            return Ok(Regex { engine: Box::new(EmptyEngine) });
        }

        // If the engine and program weren't specified, choose them automatically based on nfa.
        let engine = engine.unwrap_or(if nfa.is_anchored() {
            EngineType::Backtracking
        } else {
            EngineType::ForwardBackward
        });
        let prog = prog.unwrap_or(ProgramType::Vm);

        let eng: Box<Engine<u8>> = match engine {
            EngineType::Backtracking => {
                match prog {
                    ProgramType::Table =>
                        Box::new(try!(Regex::make_backtracking::<TableInsts<_>>(nfa, max_states))),
                    ProgramType::Vm =>
                        Box::new(try!(Regex::make_backtracking::<VmInsts<_>>(nfa, max_states))),
                }
            }
            EngineType::ForwardBackward => {
                match prog {
                    ProgramType::Table =>
                        Box::new(try!(Regex::make_forward_backward::<TableInsts<_>, TableInsts<_>>(
                                    nfa, max_states))),
                    ProgramType::Vm =>
                        Box::new(try!(Regex::make_forward_backward::<VmInsts<_>, VmInsts<_>>(
                                    nfa, max_states))),
                }
            }
        };

        Ok(Regex { engine: eng })
    }

    /// Returns the index range of the first shortest match, if there is a match. The indices
    /// returned are byte indices of the string. The first index is inclusive; the second is
    /// exclusive, and a little more subtle -- see the crate documentation.
    pub fn shortest_match(&self, s: &str) -> Option<(usize, usize)> {
        if let Some((start, end, look_behind)) = self.engine.shortest_match(s) {
            Some((start + look_behind as usize, end))
        } else {
            None
        }
    }

    pub fn is_match(&self, s: &str) -> bool {
        self.shortest_match(s).is_some()
    }
}
<commit_msg>Fallback to Becktracking if ForwardBackward fails.<commit_after>// Copyright 2015 Joe Neeman.
//
// 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.

use dfa::CompileTarget;
use error::Error;
use nfa::{Nfa, NoLooks};
use runner::forward_backward::ForwardBackwardEngine;
use runner::backtracking::BacktrackingEngine;
use runner::prefix::Prefix;
use runner::program::{Instructions, Program, TableInsts, VmInsts};
use runner::Engine;
use std;
use std::fmt::Debug;

#[derive(Debug)]
pub struct Regex {
    engine: Box<Engine<u8>>,
}

// An engine that doesn't match anything.
#[derive(Clone, Debug)]
struct EmptyEngine;

impl<Ret: Debug> Engine<Ret> for EmptyEngine {
    fn shortest_match(&self, _: &str) -> Option<(usize, usize, Ret)> { None }
    fn clone_box(&self) -> Box<Engine<Ret>> { Box::new(EmptyEngine) }
}

/// An enum listing the different kinds of supported regex engines.
#[derive(Clone, Copy, Debug)]
pub enum EngineType {
    /// The backtracking engine will attempt to match the regex starting from offset zero,
    /// then it will try again from offset one, and so on. Although it is quite fast in practice,
    /// it has a poor worst-case behavior. For example, in attempting to match the regex
    /// `"aaaaaaaaaaab"` against the string `"aaaaaaaaaaaaaaaaaaaaaaaaaaa"`, it will look at
    /// each character in the input many times.
    Backtracking,
    /// The forward-backward engine is guaranteed to look at each input character at most twice.
    ForwardBackward,
}

/// An enum listing the different ways for representing the regex program.
#[derive(Clone, Copy, Debug)]
pub enum ProgramType {
    /// A `Vm` program represents a regex as a list of instructions. It is a fairly
    /// memory-efficient representation, particularly when the regex contains lots of string
    /// literals.
    Vm,
    /// A `Table` program is the classical table-based implementation of a DFA.
    Table,
}

impl Clone for Regex {
    fn clone(&self) -> Regex {
        Regex {
            engine: self.engine.clone_box(),
        }
    }
}

impl Regex {
    /// Creates a new `Regex` from a regular expression string.
    pub fn new(re: &str) -> Result<Regex, Error> {
        Regex::new_bounded(re, std::usize::MAX)
    }

    /// Creates a new `Regex` from a regular expression string, but only if it doesn't require too
    /// many states.
    pub fn new_bounded(re: &str, max_states: usize) -> Result<Regex, Error> {
        Regex::make_regex(re, max_states, None, None)
    }

    /// Creates a new `Regex` from a regular expression string, with some additional knobs to
    /// tweak.
    ///
    /// - `engine` - specifies the search algorithm to use while executing the regex.
    /// - `program` - specifies the representation of the regex program.
    pub fn new_advanced(re: &str, max_states: usize, engine: EngineType, program: ProgramType)
    -> Result<Regex, Error>
    {
        Regex::make_regex(re, max_states, Some(engine), Some(program))
    }

    fn make_backtracking<I>(nfa: Nfa<u32, NoLooks>, max_states: usize)
    -> Result<BacktrackingEngine<I>, Error> where
    I: Instructions<Ret=u8>,
    Program<I>: CompileTarget<u8> {
        if nfa.has_look_behind() {
            return Err(Error::InvalidEngine("look-behind rules out the backtracking engine"));
        }

        let nfa = try!(nfa.byte_me(max_states));
        let dfa = try!(nfa.determinize_shortest(max_states))
            .optimize_for_shortest_match()
            .map_ret(|(_, bytes)| bytes);
        let (prog, state_map) = dfa.to_program::<Program<I>>();
        let prefix = if dfa.is_anchored() {
            Prefix::Empty
        } else {
            dfa.prefix(&state_map)
        };

        Ok(BacktrackingEngine::new(prog, prefix))
    }

    fn make_forward_backward<FI, BI>(nfa: Nfa<u32, NoLooks>, max_states: usize)
    -> Result<ForwardBackwardEngine<FI, BI>, Error> where
    FI: Instructions<Ret=(usize, u8)>,
    Program<FI>: CompileTarget<(usize, u8)>,
    BI: Instructions<Ret=u8>,
    Program<BI>: CompileTarget<u8>,
    {
        if nfa.is_anchored() {
            return Err(Error::InvalidEngine("anchors rule out the forward-backward engine"));
        }

        let f_nfa = try!(try!(nfa.clone().byte_me(max_states)).anchor_look_behind(max_states));
        let b_nfa = try!(try!(nfa.byte_me(max_states)).reverse(max_states));

        let f_dfa = try!(f_nfa.determinize_shortest(max_states))
            .cut_loop_to_init()
            .optimize_for_shortest_match()
            // Do it again, because optimize might have merged something with the initial state,
            // in which case we can cut more.
            .cut_loop_to_init()
            .optimize_for_shortest_match();
        let b_dfa = try!(b_nfa.determinize_longest(max_states))
            .optimize();
        let b_dfa = b_dfa.map_ret(|(_, bytes)| bytes);

        let (b_prog, b_state_map) = b_dfa.to_program::<Program<BI>>();
        let f_dfa = f_dfa.map_ret(|(look, bytes)| {
            let b_dfa_state = b_dfa.init[look.as_usize()].expect("BUG: back dfa must have this init");
            (b_state_map[b_dfa_state], bytes)
        });
        let (f_prog, f_state_map) = f_dfa.to_program::<Program<FI>>();

        Ok(ForwardBackwardEngine::new(f_prog, f_dfa.pruned_prefix(&f_state_map), b_prog))
    }

    // Make a forward-backward engine, but if that uses too many states and fallback is true then try
    // making a backtracking engine instead.
    fn make_boxed_forward_backward<FI, BI>(nfa: Nfa<u32, NoLooks>, max_states: usize, fallback: bool)
    -> Result<Box<Engine<u8>>, Error> where
    FI: Instructions<Ret=(usize, u8)> + 'static,
    Program<FI>: CompileTarget<(usize, u8)>,
    BI: Instructions<Ret=u8> + 'static,
    Program<BI>: CompileTarget<u8>,
    {
        let fb = Regex::make_forward_backward(nfa.clone(), max_states)
            .map(|x| Box::new(x) as Box<Engine<u8>>);
        if fallback {
            fb.or_else(|_| {
                let b = try!(Regex::make_backtracking(nfa, max_states));
                Ok(Box::new(b) as Box<Engine<u8>>)
            })
        } else {
            fb
        }
    }

    fn make_regex(re: &str,
                  max_states: usize,
                  maybe_eng: Option<EngineType>,
                  maybe_prog: Option<ProgramType>)
    -> Result<Regex, Error> {
        let nfa = try!(Nfa::from_regex(re));
        let nfa = nfa.remove_looks();

        if nfa.is_empty() {
            return Ok(Regex { engine: Box::new(EmptyEngine) });
        }

        // If the engine and program weren't specified, choose them automatically based on nfa.
        let eng = maybe_eng.unwrap_or(if nfa.is_anchored() {
            EngineType::Backtracking
        } else {
            EngineType::ForwardBackward
        });
        let prog = maybe_prog.unwrap_or(ProgramType::Vm);

        let eng: Box<Engine<u8>> = match eng {
            EngineType::Backtracking => {
                match prog {
                    ProgramType::Table =>
                        Box::new(try!(Regex::make_backtracking::<TableInsts<_>>(nfa, max_states))),
                    ProgramType::Vm =>
                        Box::new(try!(Regex::make_backtracking::<VmInsts<_>>(nfa, max_states))),
                }
            }
            EngineType::ForwardBackward => {
                match prog {
                    ProgramType::Table =>
                        try!(Regex::make_boxed_forward_backward::<TableInsts<_>, TableInsts<_>>(
                                nfa,
                                max_states,
                                maybe_eng.is_none())),
                    ProgramType::Vm =>
                        try!(Regex::make_boxed_forward_backward::<VmInsts<_>, VmInsts<_>>(
                                nfa,
                                max_states,
                                maybe_eng.is_none())),
                }
            }
        };

        Ok(Regex { engine: eng })
    }

    /// Returns the index range of the first shortest match, if there is a match. The indices
    /// returned are byte indices of the string. The first index is inclusive; the second is
    /// exclusive, and a little more subtle -- see the crate documentation.
    pub fn shortest_match(&self, s: &str) -> Option<(usize, usize)> {
        if let Some((start, end, look_behind)) = self.engine.shortest_match(s) {
            Some((start + look_behind as usize, end))
        } else {
            None
        }
    }

    pub fn is_match(&self, s: &str) -> bool {
        self.shortest_match(s).is_some()
    }
}

#[cfg(test)]
mod tests {
    use regex::*;

    #[test]
    fn size_fallback() {
        // This regex takes a huge number of states if you anchor it by adding '.*' in front.
        let re = "a[ab]{100}c";
        assert!(Regex::new_bounded(re, 2000).is_ok());
        assert!(Regex::new_advanced(re, 2000, EngineType::Backtracking, ProgramType::Vm).is_ok());
        assert!(Regex::new_advanced(re, 2000, EngineType::ForwardBackward, ProgramType::Vm).is_err());
    }
}

<|endoftext|>


<commit_before>//! 2D grid with neighbors iter and custom internal coordinate.

mod iter;
mod coord;
mod test;

use std::mem;

use scoped_threadpool::Pool;

use traits::Grid;
use traits::Cell;
use traits::EvolutionState;
use traits::Nhood;
use traits::Coord;

use self::iter::Iter;
pub use self::coord::GridCoord;

/// 2D grid. Implemented with two buffers.
/// They are swapped on every evolution step.
/// Old buffer is used for read-only neighbors data.
/// New buffer is writable and mutated through update process.
/// Grid uses one-dimensional `Vec` to store cells.
pub struct TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    cells: Vec<C>,
    old_cells: Vec<C>,
    evolution_state: C::State,
    nhood: N,
    neighbors: Vec<Vec<Option<usize>>>,
    dimensions: GridCoord,
    rows: i32,
    cols: i32,
    pool: Option<Pool>,
    separate: bool,
}

impl<C, N> TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    /// Constructs TwodimGrid with given ROWSxCOLS, neighborhood
    /// strategy, initial evolution state, threads count and separate flag.
    ///
    /// Separate flag means grid will not use thread it's called from.
    pub fn new(rows: i32,
               cols: i32,
               nhood: N,
               state: C::State,
               threads: u32,
               separate: bool)
               -> Self {

        let len = (rows * cols) as usize;

        let cells = Vec::with_capacity(len);
        let old_cells = Vec::with_capacity(len);
        let neighbors = Vec::with_capacity(len);

        let threads = if separate {
            threads
        } else {
            threads - 1
        };
        let pool = if threads > 1 {
            Some(Pool::new(threads))
        } else {
            None
        };

        let mut grid = TwodimGrid {
            cells: cells,
            old_cells: old_cells,
            evolution_state: state,
            nhood: nhood,
            neighbors: neighbors,
            rows: rows,
            cols: cols,
            dimensions: GridCoord::from_2d(cols, rows),
            pool: pool,
            separate: separate,
        };

        grid.init();

        grid
    }

    fn init(&mut self) {

        for offset in 0..self.rows * self.cols {

            let coord = GridCoord::from_offset(offset as i32, self.rows, self.cols);

            // init neighbors
            let neighbors = self.get_neighbors(&coord);
            self.neighbors.push(neighbors);

            // init cells
            let cell = C::with_coord(coord);
            self.cells.push(cell.clone());
            self.old_cells.push(cell.clone());
        }
    }

    fn get_neighbors(&self, coord: &GridCoord) -> Vec<Option<usize>> {

        let neighbors_count = self.nhood.neighbors_count();
        let mut neighbors = Vec::with_capacity(neighbors_count);

        for coord in self.nhood.neighbors(coord).iter() {

            if coord.x() >= 0 && coord.x() < self.cols && coord.y() >= 0 && coord.y() < self.rows {
                neighbors.push(Some(self.offset(coord)));
            } else {
                neighbors.push(None);
            }
        }

        neighbors
    }

    #[inline]
    fn offset<Crd: Coord>(&self, coord: &Crd) -> usize {
        (coord.y() * self.cols + coord.x()) as usize
    }
}

impl<C, N> Grid for TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    type Cell = C;
    type Coord = GridCoord;

    fn update(&mut self) {
        mem::swap(&mut self.cells, &mut self.old_cells);

        for i in 0..self.cells.len() {
            unsafe {
                let ref neighbors = self.neighbors.get_unchecked(i);
                let neighbors_iter =
                    Iter::new(&self.old_cells, &neighbors, self.nhood.neighbors_count());

                let old = self.old_cells.get_unchecked(i);
                let cell = self.cells.get_unchecked_mut(i);
                cell.update(old, neighbors_iter, &self.evolution_state);
            }
        }

        self.evolution_state.update();
    }

    fn set_cells(&mut self, new_cells: Vec<Self::Cell>) {

        for cell in new_cells.into_iter() {

            let index;

            {
                index = self.offset(cell.coord());
            }

            self.cells[index] = cell;
        }
    }

    fn cells(&self) -> &Vec<Self::Cell> { &self.cells }

    fn state(&self) -> &<<Self as Grid>::Cell as Cell>::State { &self.evolution_state }

    fn dimensions(&self) -> Self::Coord { self.dimensions.clone() }
}
<commit_msg>Grid will always run in separate thread.<commit_after>//! 2D grid with neighbors iter and custom internal coordinate.

mod iter;
mod coord;
mod test;

use std::mem;

use scoped_threadpool::Pool;

use traits::Grid;
use traits::Cell;
use traits::EvolutionState;
use traits::Nhood;
use traits::Coord;

use self::iter::Iter;
pub use self::coord::GridCoord;

/// 2D grid. Implemented with two buffers.
/// They are swapped on every evolution step.
/// Old buffer is used for read-only neighbors data.
/// New buffer is writable and mutated through update process.
/// Grid uses one-dimensional `Vec` to store cells.
pub struct TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    cells: Vec<C>,
    old_cells: Vec<C>,
    evolution_state: C::State,
    nhood: N,
    neighbors: Vec<Vec<Option<usize>>>,
    dimensions: GridCoord,
    rows: i32,
    cols: i32,
    pool: Pool,
}

impl<C, N> TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    /// Constructs TwodimGrid with given ROWSxCOLS, neighborhood
    /// strategy, initial evolution state, threads count.
    pub fn new(rows: i32, cols: i32, nhood: N, state: C::State, threads: u32) -> Self {

        let len = (rows * cols) as usize;

        let cells = Vec::with_capacity(len);
        let old_cells = Vec::with_capacity(len);
        let neighbors = Vec::with_capacity(len);

        let pool = Pool::new(threads);

        let mut grid = TwodimGrid {
            cells: cells,
            old_cells: old_cells,
            evolution_state: state,
            nhood: nhood,
            neighbors: neighbors,
            rows: rows,
            cols: cols,
            dimensions: GridCoord::from_2d(cols, rows),
            pool: pool,
        };

        grid.init();

        grid
    }

    fn init(&mut self) {

        for offset in 0..self.rows * self.cols {

            let coord = GridCoord::from_offset(offset as i32, self.rows, self.cols);

            // init neighbors
            let neighbors = self.get_neighbors(&coord);
            self.neighbors.push(neighbors);

            // init cells
            let cell = C::with_coord(coord);
            self.cells.push(cell.clone());
            self.old_cells.push(cell.clone());
        }
    }

    fn get_neighbors(&self, coord: &GridCoord) -> Vec<Option<usize>> {

        let neighbors_count = self.nhood.neighbors_count();
        let mut neighbors = Vec::with_capacity(neighbors_count);

        for coord in self.nhood.neighbors(coord).iter() {

            if coord.x() >= 0 && coord.x() < self.cols && coord.y() >= 0 && coord.y() < self.rows {
                neighbors.push(Some(self.offset(coord)));
            } else {
                neighbors.push(None);
            }
        }

        neighbors
    }

    #[inline]
    fn offset<Crd: Coord>(&self, coord: &Crd) -> usize {
        (coord.y() * self.cols + coord.x()) as usize
    }
}

impl<C, N> Grid for TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    type Cell = C;
    type Coord = GridCoord;

    fn update(&mut self) {
        mem::swap(&mut self.cells, &mut self.old_cells);

        for i in 0..self.cells.len() {
            unsafe {
                let ref neighbors = self.neighbors.get_unchecked(i);
                let neighbors_iter =
                    Iter::new(&self.old_cells, &neighbors, self.nhood.neighbors_count());

                let old = self.old_cells.get_unchecked(i);
                let cell = self.cells.get_unchecked_mut(i);
                cell.update(old, neighbors_iter, &self.evolution_state);
            }
        }

        self.evolution_state.update();
    }

    fn set_cells(&mut self, new_cells: Vec<Self::Cell>) {

        for cell in new_cells.into_iter() {

            let index;

            {
                index = self.offset(cell.coord());
            }

            self.cells[index] = cell;
        }
    }

    fn cells(&self) -> &Vec<Self::Cell> { &self.cells }

    fn state(&self) -> &<<Self as Grid>::Cell as Cell>::State { &self.evolution_state }

    fn dimensions(&self) -> Self::Coord { self.dimensions.clone() }
}
<|endoftext|>