<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;
use std::convert::From;

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 DOUBLE_SPACE_OPTION: &str = "d";
static NUMBERING_MODE_OPTION: &str = "n";
static FILE_STDIN: &str = "-";
static READ_BUFFER_SIZE: usize = 1024 * 64;

struct OutputOptions {
    /// Line numbering mode
    number: Option<NumberingMode>,
    header: String,
    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,
}

impl From<Error> for PrError {
    fn from(err: Error) -> Self {
        PrError::EncounteredErrors(err.to_string())
    }
}

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)
        }

        IsSocket(path: String) {
            display("pr: cannot open {}, Operation not supported on socket", path)
        }
    }
}

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

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

    opts.optflag(
        DOUBLE_SPACE_OPTION,
        "double-space",
        "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 = match pr(&f, options) {
            Err(error) => {
                writeln!(&mut stderr(), "{}", error);
                -1
            },
            _ => 0
        };
        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(),
        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) => {
            Err(PrError::IsSocket(path.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) -> Result<i32, PrError> {
    let mut i = 0;
    let mut page: usize = 0;
    let mut buffered_content: Vec<String> = Vec::new();

    for line in BufReader::with_capacity(READ_BUFFER_SIZE, open(path)?).lines() {
        if i == CONTENT_LINES_PER_PAGE {
            page = page + 1;
            i = 0;
            print_page(&buffered_content, options, &page)?;
            buffered_content = Vec::new();
        }
        buffered_content.push(line?);
        i = i + 1;
    }

    if i != 0 {
        page = page + 1;
        print_page(&buffered_content, options, &page)?;
    }
    return Ok(0);
}

fn print_page(lines: &Vec<String>, options: &OutputOptions, page: &usize) -> Result<usize, Error> {
    let header: Vec<String> = header_content(options, page);
    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.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();
    let mut lines_written = 0;

    out.lock();
    for x in header {
        out.write(x.as_bytes())?;
        out.write(line_separator)?;
        lines_written += 1;
    }

    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;
    }
    lines_written += i - 1;
    for x in trailer_content {
        out.write(x.as_bytes())?;
        out.write(line_separator)?;
        lines_written += 1;
    }
    out.flush()?;
    Ok(lines_written)
}

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 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)
}
<commit_msg>pr: add --page option<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;
use std::convert::From;

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 DOUBLE_SPACE_OPTION: &str = "d";
static NUMBERING_MODE_OPTION: &str = "n";
static PAGE_RANGE_OPTION: &str = "page";
static FILE_STDIN: &str = "-";
static READ_BUFFER_SIZE: usize = 1024 * 64;

struct OutputOptions {
    /// Line numbering mode
    number: Option<NumberingMode>,
    header: String,
    line_separator: String,
    last_modified_time: String,
    start_page: Option<usize>,
    end_page: Option<usize>,
}

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,
}

impl From<Error> for PrError {
    fn from(err: Error) -> Self {
        PrError::EncounteredErrors(err.to_string())
    }
}

impl From<std::num::ParseIntError> for PrError {
    fn from(err: std::num::ParseIntError) -> Self {
        PrError::EncounteredErrors(err.to_string())
    }
}

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}", msg)
        }

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

        IsSocket(path: String) {
            display("pr: cannot open {}, Operation not supported on socket", path)
        }
    }
}

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

    opts.optflagopt(
        "",
        PAGE_RANGE_OPTION,
        "Begin and stop printing with page FIRST_PAGE[:LAST_PAGE]",
        "FIRST_PAGE[:LAST_PAGE]",
    );

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

    opts.optflag(
        DOUBLE_SPACE_OPTION,
        "double-space",
        "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 result_options = build_options(&matches, header, &f);
        if result_options.is_err() {
            writeln!(&mut stderr(), "{}", result_options.err().unwrap());
            return 1;
        }
        let options = &result_options.unwrap();
        let status: i32 = match pr(&f, options) {
            Err(error) => {
                writeln!(&mut stderr(), "{}", error);
                1
            }
            _ => 0
        };
        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) -> Result<OutputOptions, PrError> {
    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)
    };

    let start_page = match matches.opt_str(PAGE_RANGE_OPTION).map(|i| {
        let x: Vec<&str> = i.split(":").collect();
        x[0].parse::<usize>()
    }) {
        Some(res) => Some(res?),
        _ => None
    };

    let end_page = match matches.opt_str(PAGE_RANGE_OPTION)
        .filter(|i| i.contains(":"))
        .map(|i| {
            let x: Vec<&str> = i.split(":").collect();
            x[1].parse::<usize>()
        }) {
        Some(res) => Some(res?),
        _ => None
    };

    if start_page.is_some() && end_page.is_some() && start_page.unwrap() > end_page.unwrap() {
        return Err(PrError::EncounteredErrors(format!("invalid page range ‘{}:{}’", start_page.unwrap(), end_page.unwrap())));
    }

    Ok(OutputOptions {
        number: numbering_options,
        header: header.to_string(),
        line_separator,
        last_modified_time,
        start_page,
        end_page,
    })
}

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) => {
            Err(PrError::IsSocket(path.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) -> Result<i32, PrError> {
    let mut i = 0;
    let mut page: usize = 0;
    let mut buffered_content: Vec<String> = Vec::new();

    for line in BufReader::with_capacity(READ_BUFFER_SIZE, open(path)?).lines() {
        if i == CONTENT_LINES_PER_PAGE {
            page = page + 1;
            i = 0;
            print_page(&buffered_content, options, &page)?;
            buffered_content = Vec::new();
        }
        buffered_content.push(line?);
        i = i + 1;
    }

    if i != 0 {
        page = page + 1;
        print_page(&buffered_content, options, &page)?;
    }
    return Ok(0);
}

fn print_page(lines: &Vec<String>, options: &OutputOptions, page: &usize) -> Result<usize, Error> {
    let start_page = options.as_ref().start_page.as_ref();
    let last_page = options.as_ref().end_page.as_ref();
    let is_within_print_range = (start_page.is_none() || page >= start_page.unwrap()) &&
        (last_page.is_none() || page <= last_page.unwrap());
    if !is_within_print_range {
        return Ok(0);
    }
    let header: Vec<String> = header_content(options, page);
    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.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();
    let mut lines_written = 0;

    out.lock();
    for x in header {
        out.write(x.as_bytes())?;
        out.write(line_separator)?;
        lines_written += 1;
    }

    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;
    }
    lines_written += i - 1;
    for x in trailer_content {
        out.write(x.as_bytes())?;
        out.write(line_separator)?;
        lines_written += 1;
    }
    out.flush()?;
    Ok(lines_written)
}

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 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>use std::collections::{HashSet,HashMap};
use uuid::Uuid;

use graphics::{ Graphics, ImageSize };
use graphics::math::{ Matrix2d };

use input::GenericEvent;
use ai_behavior::{
    Behavior,
    State,
    Running,
};

use sprite::Sprite;

use animation::{
    Animation,
    AnimationState,
};

/// A scene is used to manage sprite's life and run animation with sprite
pub struct Scene<I: ImageSize> {
    children: Vec<Sprite<I>>,
    children_index: HashMap<Uuid, usize>,
    running: HashMap<Uuid,
        Vec<(Behavior<Animation>, State<Animation, AnimationState>, bool)>>,
    // Set of sprites that should be removed once animations have finished.
    dead_sprites: HashSet<Uuid>,
}

impl<I: ImageSize> Scene<I> {
    /// Create a new scene
    pub fn new() -> Scene<I> {
        Scene {
            children: Vec::new(),
            children_index: HashMap::new(),
            running: HashMap::new(),
            dead_sprites: HashSet::new(),
        }
    }

    /// Update animation's state
    pub fn event<E>(&mut self, e: &E) where E: GenericEvent {
        // regenerate the animations and their states
        let running = self.running.clone();
        self.running.clear();

        for (id, animations) in running.into_iter() {
            let mut new_animations = Vec::new();

            for (b, mut a, paused) in animations.into_iter() {
                if paused {
                    new_animations.push((b, a, paused));
                    continue;
                }

                let sprite = self.child_mut(id).unwrap();
                let (status, _) = a.event(e, &mut |args| {
                    let (state, status, remain) = {
                        let start_state;
                        let state = match *args.state {
                            None => { start_state = args.action.to_state(sprite); &start_state },
                            Some(ref state) => state,
                        };
                        state.update(sprite, args.dt)
                    };
                    *args.state = state;
                    (status, remain)
                });

                match status {
                    // the behavior is still running, add it for next update
                    Running => {
                        new_animations.push((b, a, paused));
                    },
                    _ => {},
                }
            }

            if !new_animations.is_empty() {
                self.running.insert(id, new_animations);
            }
        }

        self.prune_dead_sprites();
    }

    fn prune_dead_sprites(&mut self) {
        if !self.dead_sprites.is_empty() {
            let mut to_remove = HashSet::new();

            for sprite_id in self.dead_sprites.iter() {
                let n = self.running_for_child(*sprite_id)
                    .expect("Assert failed: invalid internal state for dead_sprites");

                if n == 0 {
                    to_remove.insert(*sprite_id);
                }
            }

            for sprite_id in to_remove.iter() {
                self.remove_child(*sprite_id);
            }
        }
    }

    /// Render this scene
    pub fn draw<B: Graphics<Texture = I>>(&self, t: Matrix2d, b: &mut B) {
        for child in &self.children {
            child.draw(t, b);
        }
    }

    /// Render this scene with tint
    pub fn draw_tinted<B: Graphics<Texture = I>>(&self, t: Matrix2d, b: &mut B, c: [f32;3]) {
        for child in &self.children {
            child.draw_tinted(t,b,c)
        }
    }

    /// Register animation with sprite
    pub fn run(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        use std::collections::hash_map::Entry::{ Vacant, Occupied };
        let animations = match self.running.entry(sprite_id) {
            Vacant(entry) => entry.insert(Vec::new()),
            Occupied(entry) => entry.into_mut()
        };
        let state = State::new(animation.clone());
        animations.push((animation.clone(), state, false));
    }

    fn find(&self, sprite_id: Uuid, animation: &Behavior<Animation>) -> Option<usize> {
        let mut index = None;
        if let Some(animations) = self.running.get(&sprite_id) {
            for (i, &(ref b, _, _)) in animations.iter().enumerate() {
                if b == animation {
                    index = Some(i);
                    break;
                }
            }
        }
        index
    }

    /// Pause a running animation of the sprite
    pub fn pause(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, true));
        }
    }

    /// Resume a paused animation of the sprite
    pub fn resume(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, false));
        }
    }

    /// Toggle an animation of the sprite
    pub fn toggle(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, paused) = animations.remove(index);
            animations.push((b, s, !paused));
        }
    }

    /// Stop a running animation of the sprite
    pub fn stop(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            self.running.get_mut(&sprite_id).unwrap().remove(index);
        }
    }

    /// Stop all running animations of the sprite
    pub fn stop_all(&mut self, sprite_id: Uuid) {
        self.running.remove(&sprite_id);
    }

    /// Get all the running animations in the scene
    pub fn running(&self) -> usize {
        let mut total = 0;
        for (_, animations) in &self.running {
            total += animations.len();
        }
        total
    }

    /// Get the number of running animations for a sprite. If sprite does not
    /// exist, returns None.
    pub fn running_for_child(&self, sprite_id: Uuid) -> Option<usize> {
        if let Some(animations) = self.running.get(&sprite_id) {
            Some(animations.len())
        } else {
            if self.child(sprite_id).is_some() {
                Some(0)
            } else {
                None
            }
        }
    }

    /// Add sprite to scene
    pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
        let id = sprite.id();
        self.children.push(sprite);
        self.children_index.insert(id.clone(), self.children.len() - 1);
        id
    }

    fn stop_all_including_children(&mut self, sprite: &Sprite<I>) {
        self.stop_all(sprite.id());
        for child in sprite.children().iter() {
            self.stop_all_including_children(child);
        }
    }

    /// Remove the child by `id` from the scene's children or grandchild
    /// will stop all the animations run by this child
    pub fn remove_child(&mut self, id: Uuid) -> Option<Sprite<I>> {
        let removed = if let Some(index) = self.children_index.remove(&id) {
            let removed = self.children.remove(index);
            // Removing a element of vector will alter the index,
            // update the mapping from uuid to index.
            for i in index..self.children.len() {
                let uuid = self.children[i].id();
                self.children_index.insert(uuid, i);
            }
            Some(removed)
        } else {
            for child in &mut self.children {
                if let Some(c) = child.remove_child(id.clone()) {
                    return Some(c);
                }
            }
            None
        };

        if removed.is_some() {
            self.dead_sprites.remove(&id);
            self.stop_all_including_children(removed.as_ref().unwrap());
        }

        removed
    }

    /// Remove the child by `id` from the scene's children or grandchild once
    /// all of its animations have finished. If the child current has no
    /// animations, it is removed immediately. Children with paused animations
    /// will not be removed until the animations are resumed and completed.
    pub fn remove_child_when_done(&mut self, id: Uuid) {
        match self.running_for_child(id) {
            Some(n) => {
                if n == 0 {
                    self.remove_child(id);
                } else {
                    self.dead_sprites.insert(id);
                }
            },
            None => {}
        }
    }

    /// Find the child by `id` from the scene's children or grandchild
    pub fn child(&self, id: Uuid) -> Option<&Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&self.children[*index])
        } else {
            for child in &self.children {
                if let Some(c) = child.child(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild, mutability
    pub fn child_mut(&mut self, id: Uuid) -> Option<&mut Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&mut self.children[*index])
        } else {
            for child in &mut self.children {
                if let Some(c) = child.child_mut(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Get the list of top-level (non-child) sprites.
    #[inline(always)]
    pub fn children(&self) -> &Vec<Sprite<I>> {
        &self.children
    }
}
<commit_msg>Use mem::take to replace clone+clear<commit_after>use std::collections::{HashSet,HashMap};
use std::mem;
use uuid::Uuid;

use graphics::{ Graphics, ImageSize };
use graphics::math::{ Matrix2d };

use input::GenericEvent;
use ai_behavior::{
    Behavior,
    State,
    Running,
};

use sprite::Sprite;

use animation::{
    Animation,
    AnimationState,
};

/// A scene is used to manage sprite's life and run animation with sprite
pub struct Scene<I: ImageSize> {
    children: Vec<Sprite<I>>,
    children_index: HashMap<Uuid, usize>,
    running: HashMap<Uuid,
        Vec<(Behavior<Animation>, State<Animation, AnimationState>, bool)>>,
    // Set of sprites that should be removed once animations have finished.
    dead_sprites: HashSet<Uuid>,
}

impl<I: ImageSize> Scene<I> {
    /// Create a new scene
    pub fn new() -> Scene<I> {
        Scene {
            children: Vec::new(),
            children_index: HashMap::new(),
            running: HashMap::new(),
            dead_sprites: HashSet::new(),
        }
    }

    /// Update animation's state
    pub fn event<E>(&mut self, e: &E) where E: GenericEvent {
        // regenerate the animations and their states
        let running = mem::take(&mut self.running);

        for (id, animations) in running.into_iter() {
            let mut new_animations = Vec::new();

            for (b, mut a, paused) in animations.into_iter() {
                if paused {
                    new_animations.push((b, a, paused));
                    continue;
                }

                let sprite = self.child_mut(id).unwrap();
                let (status, _) = a.event(e, &mut |args| {
                    let (state, status, remain) = {
                        let start_state;
                        let state = match *args.state {
                            None => { start_state = args.action.to_state(sprite); &start_state },
                            Some(ref state) => state,
                        };
                        state.update(sprite, args.dt)
                    };
                    *args.state = state;
                    (status, remain)
                });

                match status {
                    // the behavior is still running, add it for next update
                    Running => {
                        new_animations.push((b, a, paused));
                    },
                    _ => {},
                }
            }

            if !new_animations.is_empty() {
                self.running.insert(id, new_animations);
            }
        }

        self.prune_dead_sprites();
    }

    fn prune_dead_sprites(&mut self) {
        if !self.dead_sprites.is_empty() {
            let mut to_remove = HashSet::new();

            for sprite_id in self.dead_sprites.iter() {
                let n = self.running_for_child(*sprite_id)
                    .expect("Assert failed: invalid internal state for dead_sprites");

                if n == 0 {
                    to_remove.insert(*sprite_id);
                }
            }

            for sprite_id in to_remove.iter() {
                self.remove_child(*sprite_id);
            }
        }
    }

    /// Render this scene
    pub fn draw<B: Graphics<Texture = I>>(&self, t: Matrix2d, b: &mut B) {
        for child in &self.children {
            child.draw(t, b);
        }
    }

    /// Render this scene with tint
    pub fn draw_tinted<B: Graphics<Texture = I>>(&self, t: Matrix2d, b: &mut B, c: [f32;3]) {
        for child in &self.children {
            child.draw_tinted(t,b,c)
        }
    }

    /// Register animation with sprite
    pub fn run(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        use std::collections::hash_map::Entry::{ Vacant, Occupied };
        let animations = match self.running.entry(sprite_id) {
            Vacant(entry) => entry.insert(Vec::new()),
            Occupied(entry) => entry.into_mut()
        };
        let state = State::new(animation.clone());
        animations.push((animation.clone(), state, false));
    }

    fn find(&self, sprite_id: Uuid, animation: &Behavior<Animation>) -> Option<usize> {
        let mut index = None;
        if let Some(animations) = self.running.get(&sprite_id) {
            for (i, &(ref b, _, _)) in animations.iter().enumerate() {
                if b == animation {
                    index = Some(i);
                    break;
                }
            }
        }
        index
    }

    /// Pause a running animation of the sprite
    pub fn pause(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, true));
        }
    }

    /// Resume a paused animation of the sprite
    pub fn resume(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, _) = animations.remove(index);
            animations.push((b, s, false));
        }
    }

    /// Toggle an animation of the sprite
    pub fn toggle(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            let animations = self.running.get_mut(&sprite_id).unwrap();
            let (b, s, paused) = animations.remove(index);
            animations.push((b, s, !paused));
        }
    }

    /// Stop a running animation of the sprite
    pub fn stop(&mut self, sprite_id: Uuid, animation: &Behavior<Animation>) {
        if let Some(index) = self.find(sprite_id, animation) {
            self.running.get_mut(&sprite_id).unwrap().remove(index);
        }
    }

    /// Stop all running animations of the sprite
    pub fn stop_all(&mut self, sprite_id: Uuid) {
        self.running.remove(&sprite_id);
    }

    /// Get all the running animations in the scene
    pub fn running(&self) -> usize {
        let mut total = 0;
        for (_, animations) in &self.running {
            total += animations.len();
        }
        total
    }

    /// Get the number of running animations for a sprite. If sprite does not
    /// exist, returns None.
    pub fn running_for_child(&self, sprite_id: Uuid) -> Option<usize> {
        if let Some(animations) = self.running.get(&sprite_id) {
            Some(animations.len())
        } else {
            if self.child(sprite_id).is_some() {
                Some(0)
            } else {
                None
            }
        }
    }

    /// Add sprite to scene
    pub fn add_child(&mut self, sprite: Sprite<I>) -> Uuid {
        let id = sprite.id();
        self.children.push(sprite);
        self.children_index.insert(id.clone(), self.children.len() - 1);
        id
    }

    fn stop_all_including_children(&mut self, sprite: &Sprite<I>) {
        self.stop_all(sprite.id());
        for child in sprite.children().iter() {
            self.stop_all_including_children(child);
        }
    }

    /// Remove the child by `id` from the scene's children or grandchild
    /// will stop all the animations run by this child
    pub fn remove_child(&mut self, id: Uuid) -> Option<Sprite<I>> {
        let removed = if let Some(index) = self.children_index.remove(&id) {
            let removed = self.children.remove(index);
            // Removing a element of vector will alter the index,
            // update the mapping from uuid to index.
            for i in index..self.children.len() {
                let uuid = self.children[i].id();
                self.children_index.insert(uuid, i);
            }
            Some(removed)
        } else {
            for child in &mut self.children {
                if let Some(c) = child.remove_child(id.clone()) {
                    return Some(c);
                }
            }
            None
        };

        if removed.is_some() {
            self.dead_sprites.remove(&id);
            self.stop_all_including_children(removed.as_ref().unwrap());
        }

        removed
    }

    /// Remove the child by `id` from the scene's children or grandchild once
    /// all of its animations have finished. If the child current has no
    /// animations, it is removed immediately. Children with paused animations
    /// will not be removed until the animations are resumed and completed.
    pub fn remove_child_when_done(&mut self, id: Uuid) {
        match self.running_for_child(id) {
            Some(n) => {
                if n == 0 {
                    self.remove_child(id);
                } else {
                    self.dead_sprites.insert(id);
                }
            },
            None => {}
        }
    }

    /// Find the child by `id` from the scene's children or grandchild
    pub fn child(&self, id: Uuid) -> Option<&Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&self.children[*index])
        } else {
            for child in &self.children {
                if let Some(c) = child.child(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Find the child by `id` from this sprite's children or grandchild, mutability
    pub fn child_mut(&mut self, id: Uuid) -> Option<&mut Sprite<I>> {
        if let Some(index) = self.children_index.get(&id) {
            Some(&mut self.children[*index])
        } else {
            for child in &mut self.children {
                if let Some(c) = child.child_mut(id.clone()) {
                    return Some(c);
                }
            }
            None
        }
    }

    /// Get the list of top-level (non-child) sprites.
    #[inline(always)]
    pub fn children(&self) -> &Vec<Sprite<I>> {
        &self.children
    }
}
<|endoftext|>


<commit_before>use crate::graphics::*;

/// A struct containing all the necessary info for drawing a [`Drawable`](trait.Drawable.html).
///
/// This struct implements the `Default` trait, so to set only some parameter
/// you can just do:
///
/// ```rust
/// # use ggez::*;
/// # use ggez::graphics::*;
/// # fn t<P>(ctx: &mut Context, drawable: &P) where P: Drawable {
/// let my_dest = mint::Point2::new(13.0, 37.0);
/// graphics::draw(ctx, drawable, DrawParam::default().dest(my_dest) );
/// # }
/// ```
///
/// As a shortcut, it also implements `From` for a variety of tuple types.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DrawParam {
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image `(0,0 to 1,1)` if omitted.
    pub src: Rect,
    /// The position to draw the graphic expressed as a `Point2`.
    pub dest: mint::Point2<f32>,
    /// The orientation of the graphic in radians.
    pub rotation: f32,
    /// The x/y scale factors expressed as a `Vector2`.
    pub scale: mint::Vector2<f32>,
    /// An offset from the center for transform operations like scale/rotation,
    /// with `0,0` meaning the origin and `1,1` meaning the opposite corner from the origin.
    /// By default these operations are done from the top-left corner, so to rotate something
    /// from the center specify `Point2::new(0.5, 0.5)` here.
    pub offset: mint::Point2<f32>,
    /// A color to draw the target with.
    /// Default: white.
    pub color: Color,
}

impl Default for DrawParam {
    fn default() -> Self {
        DrawParam {
            src: Rect::one(),
            dest: mint::Point2 { x: 0.0, y: 0.0 },
            rotation: 0.0,
            scale: mint::Vector2 { x: 1.0, y: 1.0 },
            offset: mint::Point2 { x: 0.0, y: 0.0 },
            color: WHITE,
        }
    }
}

impl DrawParam {
    /// Create a new DrawParam with default values.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the source rect
    pub fn src(mut self, src: Rect) -> Self {
        self.src = src;
        self
    }

    /// Set the dest point
    pub fn dest<P>(mut self, dest: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = dest.into();
        self.dest = p;
        self
    }

    /// Set the drawable color.  This will be blended with whatever
    /// color the drawn object already is.
    pub fn color(mut self, color: Color) -> Self {
        self.color = color;
        self
    }

    /// Set the rotation of the drawable.
    pub fn rotation(mut self, rotation: f32) -> Self {
        self.rotation = rotation;
        self
    }

    /// Set the scaling factors of the drawable.
    pub fn scale<V>(mut self, scale: V) -> Self
    where
        V: Into<mint::Vector2<f32>>,
    {
        let p: mint::Vector2<f32> = scale.into();
        self.scale = p;
        self
    }

    /// Set the transformation offset of the drawable.
    pub fn offset<P>(mut self, offset: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = offset.into();
        self.offset = p;
        self
    }

    /// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single matrix.
    fn to_na_matrix(&self) -> Matrix4 {
        // Calculate a matrix equivalent to doing this:
        //  type Vec3 = na::Vector3<f32>;
        //  let translate = Matrix4::new_translation(&Vec3::new(self.dest.x, self.dest.y, 0.0));
        //  let offset = Matrix4::new_translation(&Vec3::new(self.offset.x, self.offset.y, 0.0));
        //  let offset_inverse =
        //      Matrix4::new_translation(&Vec3::new(-self.offset.x, -self.offset.y, 0.0));
        //  let axis_angle = Vec3::z() * self.rotation;
        //  let rotation = Matrix4::new_rotation(axis_angle);
        //  let scale = Matrix4::new_nonuniform_scaling(&Vec3::new(self.scale.x, self.scale.y, 1.0));
        //  translate * offset * rotation * scale * offset_inverse
        let cosr = self.rotation.cos();
        let sinr = self.rotation.sin();
        let m00 = cosr * self.scale.x;
        let m01 = -sinr * self.scale.y;
        let m10 = sinr * self.scale.x;
        let m11 = cosr * self.scale.y;
        let m03 = self.offset.x * (1.0 - m00) - self.offset.y * m01 + self.dest.x;
        let m13 = self.offset.y * (1.0 - m11) - self.offset.x * m10 + self.dest.y;
        // Welp, this transpose fixes some bug that makes nothing draw,
        // that was introduced in commit 2c6b3cc03f34fb240f4246f5a68c75bd85b60eae.
        // The best part is, I don't know if this code is wrong, or whether there's
        // some reversed matrix multiply or such somewhere else that this cancel
        // out.  Probably the former though.
        Matrix4::from_cols_array(&[
            m00, m01, 0.0, m03, // oh rustfmt you so fine
            m10, m11, 0.0, m13, // you so fine you blow my mind
            0.0, 0.0, 1.0, 0.0, // but leave my matrix formatting alone
            0.0, 0.0, 0.0, 1.0, // plz
        ])
        .transpose()
    }

    /// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single
    ///matrix.  Because of this it only contains the transform part (rotation/scale/etc),
    /// with no src/dest/color info.
    pub fn to_matrix(&self) -> mint::ColumnMatrix4<f32> {
        self.to_na_matrix().into()
    }
}

/// Create a `DrawParam` from a location.
/// Note that this takes a single-element tuple.
/// It's a little weird but keeps the trait implementations
/// from clashing.
impl<P> From<(P,)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from(location: (P,)) -> Self {
        DrawParam::new().dest(location.0)
    }
}

/// Create a `DrawParam` from a location and color
impl<P> From<(P, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, color): (P, Color)) -> Self {
        DrawParam::new().dest(location).color(color)
    }
}

/// Create a `DrawParam` from a location, rotation and color
impl<P> From<(P, f32, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, rotation, color): (P, f32, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .color(color)
    }
}

/// Create a `DrawParam` from a location, rotation, offset and color
impl<P> From<(P, f32, P, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, rotation, offset, color): (P, f32, P, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .color(color)
    }
}

/// Create a `DrawParam` from a location, rotation, offset, scale and color
impl<P, V> From<(P, f32, P, V, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
    V: Into<mint::Vector2<f32>>,
{
    fn from((location, rotation, offset, scale, color): (P, f32, P, V, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .scale(scale)
            .color(color)
    }
}

/// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single matrix.
/// This is a lot less useful for doing transformations than I'd hoped; basically, we sometimes
/// have to modify parameters of a `DrawParam` based *on* the parameters of a `DrawParam`, for
/// instance when scaling images so that they are in units of pixels.  This makes it really
/// hard to extract scale and rotation and such, so meh.
///
/// It's still useful for a couple internal things though, so it's kept around.
#[derive(Debug, Copy, Clone, PartialEq)]
pub(crate) struct DrawTransform {
    /// The transform matrix for the DrawParams
    pub matrix: Matrix4,
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image (1.0) if omitted.
    pub src: Rect,
    /// A color to draw the target with.
    /// Default: white.
    pub color: Color,
}

impl Default for DrawTransform {
    fn default() -> Self {
        DrawTransform {
            matrix: Matrix4::identity(),
            src: Rect::one(),
            color: WHITE,
        }
    }
}

impl From<DrawParam> for DrawTransform {
    fn from(param: DrawParam) -> Self {
        // TODO: Double-check this all lines up
        let transform = param.to_na_matrix();
        DrawTransform {
            src: param.src,
            color: param.color,
            matrix: transform,
        }
    }
}

impl DrawTransform {
    pub(crate) fn to_instance_properties(&self, srgb: bool) -> InstanceProperties {
        // TODO: Verify 'row arrays' is correct here.
        let mat: [[f32; 4]; 4] = self.matrix.to_cols_array_2d();
        let color: [f32; 4] = if srgb {
            let linear_color: types::LinearColor = self.color.into();
            linear_color.into()
        } else {
            self.color.into()
        };
        InstanceProperties {
            src: self.src.into(),
            col1: mat[0],
            col2: mat[1],
            col3: mat[2],
            col4: mat[3],
            color,
        }
    }
}
<commit_msg>Ok let's try this again<commit_after>use crate::graphics::*;

/// A struct that represents where to put a `Drawable`.
///
/// This can either be a set of individual components, or
/// a single `Matrix4` transform.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Transform {
    /// Transform made of individual values
    Values {
        /// The position to draw the graphic expressed as a `Point2`.
        dest: mint::Point2<f32>,
        /// The orientation of the graphic in radians.
        rotation: f32,
        /// The x/y scale factors expressed as a `Vector2`.
        scale: mint::Vector2<f32>,
        /// An offset from the center for transform operations like scale/rotation,
        /// with `0,0` meaning the origin and `1,1` meaning the opposite corner from the origin.
        /// By default these operations are done from the top-left corner, so to rotate something
        /// from the center specify `Point2::new(0.5, 0.5)` here.
        offset: mint::Point2<f32>,
    },
    /// Transform made of an arbitrary matrix
    Matrix(mint::ColumnMatrix4<f32>),
}

impl Default for Transform {
    fn default() -> Self {
        Transform::Values {
            dest: mint::Point2 { x: 0.0, y: 0.0 },
            rotation: 0.0,
            scale: mint::Vector2 { x: 1.0, y: 1.0 },
            offset: mint::Point2 { x: 0.0, y: 0.0 },
        }
    }
}

impl Transform {
    /// Crunches the transform down to a single matrix, if it's not one already.
    pub fn to_matrix(&self) -> Self {
        Transform::Matrix(self.to_bare_matrix())
    }

    pub fn to_bare_matrix(&self) -> mint::ColumnMatrix4<f32> {
        match self {
            Transform::Matrix(m) => *m,
            Transform::Values {
                dest,
                rotation,
                scale,
                offset,
            } => {
                // Calculate a matrix equivalent to doing this:
                //  type Vec3 = na::Vector3<f32>;
                //  let translate = Matrix4::new_translation(&Vec3::new(self.dest.x, self.dest.y, 0.0));
                //  let offset = Matrix4::new_translation(&Vec3::new(self.offset.x, self.offset.y, 0.0));
                //  let offset_inverse =
                //      Matrix4::new_translation(&Vec3::new(-self.offset.x, -self.offset.y, 0.0));
                //  let axis_angle = Vec3::z() * self.rotation;
                //  let rotation = Matrix4::new_rotation(axis_angle);
                //  let scale = Matrix4::new_nonuniform_scaling(&Vec3::new(self.scale.x, self.scale.y, 1.0));
                //  translate * offset * rotation * scale * offset_inverse
                let cosr = rotation.cos();
                let sinr = rotation.sin();
                let m00 = cosr * scale.x;
                let m01 = -sinr * scale.y;
                let m10 = sinr * scale.x;
                let m11 = cosr * scale.y;
                let m03 = offset.x * (1.0 - m00) - offset.y * m01 + dest.x;
                let m13 = offset.y * (1.0 - m11) - offset.x * m10 + dest.y;
                // Welp, this transpose fixes some bug that makes nothing draw,
                // that was introduced in commit 2c6b3cc03f34fb240f4246f5a68c75bd85b60eae.
                // The best part is, I don't know if this code is wrong, or whether there's
                // some reversed matrix multiply or such somewhere else that this cancel
                // out.  Probably the former though.
                Matrix4::from_cols_array(&[
                    m00, m01, 0.0, m03, // oh rustfmt you so fine
                    m10, m11, 0.0, m13, // you so fine you blow my mind
                    0.0, 0.0, 1.0, 0.0, // but leave my matrix formatting alone
                    0.0, 0.0, 0.0, 1.0, // plz
                ])
                .transpose()
                .into()
            }
        }
    }
}

/// A struct containing all the necessary info for drawing a [`Drawable`](trait.Drawable.html).
///
/// This struct implements the `Default` trait, so to set only some parameter
/// you can just do:
///
/// ```rust
/// # use ggez::*;
/// # use ggez::graphics::*;
/// # fn t<P>(ctx: &mut Context, drawable: &P) where P: Drawable {
/// let my_dest = mint::Point2::new(13.0, 37.0);
/// graphics::draw(ctx, drawable, DrawParam::default().dest(my_dest) );
/// # }
/// ```
///
/// As a shortcut, it also implements `From` for a variety of tuple types.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DrawParam {
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image `(0,0 to 1,1)` if omitted.
    pub src: Rect,
    /// Default: white.
    pub color: Color,
    /// Where to put the `Drawable`.
    pub trans: Transform,
}

impl Default for DrawParam {
    fn default() -> Self {
        DrawParam {
            src: Rect::one(),
            color: WHITE,
            trans: Transform::default(),
        }
    }
}

impl DrawParam {
    /// Create a new DrawParam with default values.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the source rect
    pub fn src(mut self, src: Rect) -> Self {
        self.src = src;
        self
    }

    /// Set the dest point
    pub fn dest<P>(mut self, dest: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = dest.into();
        if let Transform::Values { ref mut dest, .. } = self.trans {
            *dest = p;
            self
        } else {
            panic!("Cannot set values for a DrawParam matrix")
        }
    }

    /// Set the drawable color.  This will be blended with whatever
    /// color the drawn object already is.
    pub fn color(mut self, color: Color) -> Self {
        self.color = color;
        self
    }

    /// Set the rotation of the drawable.
    pub fn rotation(mut self, rot: f32) -> Self {
        if let Transform::Values {
            ref mut rotation, ..
        } = self.trans
        {
            *rotation = rot;
            self
        } else {
            panic!("Cannot set values for a DrawParam matrix")
        }
    }

    /// Set the scaling factors of the drawable.
    pub fn scale<V>(mut self, scale: V) -> Self
    where
        V: Into<mint::Vector2<f32>>,
    {
        let p: mint::Vector2<f32> = scale.into();
        if let Transform::Values { ref mut scale, .. } = self.trans {
            *scale = p;
            self
        } else {
            panic!("Cannot set values for a DrawParam matrix")
        }
    }

    /// Set the transformation offset of the drawable.
    pub fn offset<P>(mut self, offset: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        let p: mint::Point2<f32> = offset.into();
        if let Transform::Values { ref mut offset, .. } = self.trans {
            *offset = p;
            self
        } else {
            panic!("Cannot set values for a DrawParam matrix")
        }
    }
}

/// Create a `DrawParam` from a location.
/// Note that this takes a single-element tuple.
/// It's a little weird but keeps the trait implementations
/// from clashing.
impl<P> From<(P,)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from(location: (P,)) -> Self {
        DrawParam::new().dest(location.0)
    }
}

/// Create a `DrawParam` from a location and color
impl<P> From<(P, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, color): (P, Color)) -> Self {
        DrawParam::new().dest(location).color(color)
    }
}

/// Create a `DrawParam` from a location, rotation and color
impl<P> From<(P, f32, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, rotation, color): (P, f32, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .color(color)
    }
}

/// Create a `DrawParam` from a location, rotation, offset and color
impl<P> From<(P, f32, P, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from((location, rotation, offset, color): (P, f32, P, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .color(color)
    }
}

/// Create a `DrawParam` from a location, rotation, offset, scale and color
impl<P, V> From<(P, f32, P, V, Color)> for DrawParam
where
    P: Into<mint::Point2<f32>>,
    V: Into<mint::Vector2<f32>>,
{
    fn from((location, rotation, offset, scale, color): (P, f32, P, V, Color)) -> Self {
        DrawParam::new()
            .dest(location)
            .rotation(rotation)
            .offset(offset)
            .scale(scale)
            .color(color)
    }
}

/// A [`DrawParam`](struct.DrawParam.html) that has been crunched down to a single matrix.
/// This is a lot less useful for doing transformations than I'd hoped; basically, we sometimes
/// have to modify parameters of a `DrawParam` based *on* the parameters of a `DrawParam`, for
/// instance when scaling images so that they are in units of pixels.  This makes it really
/// hard to extract scale and rotation and such, so meh.
///
/// It's still useful for a couple internal things though, so it's kept around.
#[derive(Debug, Copy, Clone, PartialEq)]
pub(crate) struct DrawTransform {
    /// The transform matrix for the DrawParams
    pub matrix: Matrix4,
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image (1.0) if omitted.
    pub src: Rect,
    /// A color to draw the target with.
    /// Default: white.
    pub color: Color,
}

impl Default for DrawTransform {
    fn default() -> Self {
        DrawTransform {
            matrix: Matrix4::identity(),
            src: Rect::one(),
            color: WHITE,
        }
    }
}

impl From<DrawParam> for DrawTransform {
    fn from(param: DrawParam) -> Self {
        // TODO: Double-check this all lines up
        let transform = param.trans.to_bare_matrix();
        DrawTransform {
            src: param.src,
            color: param.color,
            matrix: transform.into(),
        }
    }
}

impl DrawTransform {
    pub(crate) fn to_instance_properties(&self, srgb: bool) -> InstanceProperties {
        // TODO: Verify 'row arrays' is correct here.
        let mat: [[f32; 4]; 4] = self.matrix.to_cols_array_2d();
        let color: [f32; 4] = if srgb {
            let linear_color: types::LinearColor = self.color.into();
            linear_color.into()
        } else {
            self.color.into()
        };
        InstanceProperties {
            src: self.src.into(),
            col1: mat[0],
            col2: mat[1],
            col3: mat[2],
            col4: mat[3],
            color,
        }
    }
}
<|endoftext|>


<commit_before>use common::combinator;
use std::result;
use lexer::types::*;

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

#[derive(Debug)]
pub struct ParseError {
    message: String,
    token: Option<Token>,
}

pub struct Parser {
    input: Vec<Token>,
    cursor: usize,
    saved_cursor: usize,
}

impl Parser {
    pub fn new(input: Vec<Token>) -> Parser {
        Parser {
            input: input,
            cursor: 0,
            saved_cursor: 0,
        }
    }
}

impl combinator::Parser<Token, ParseError> for Parser {
    fn consume(&mut self) -> Option<Token> {
        match self.input.get(self.cursor) {
            Some(token) => {
                self.cursor += 1;
                Some(token.clone())
            }
            None => None,
        }
    }

    fn preview(&self) -> Option<&Token> {
        self.input.get(self.cursor)
    }

    fn current_pos(&self) -> (i32, i32) {
        self.preview().unwrap().pos()
    }

    fn error<S: Into<String>>(&self, message: S) -> ParseError {
        ParseError {
            message: message.into(),
            token: if self.cursor > 0 {
                self.input.get(self.cursor - 1).map(|token| token.clone())
            } else {
                None
            },
        }
    }

    fn save(&mut self) {
        self.saved_cursor = self.cursor;
    }

    fn load(&mut self) {
        self.cursor = self.saved_cursor;
    }
}
<commit_msg>Fix typo in parser types<commit_after>use common::combinator;
use std::result;
use lexer::types::*;

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

#[derive(Debug)]
pub struct ParseError {
    message: String,
    token: Option<Token>,
}

pub struct Parser {
    input: Vec<Token>,
    cursor: usize,
    saved_cursor: usize,
}

impl Parser {
    pub fn new(input: Vec<Token>) -> Parser {
        Parser {
            input: input,
            cursor: 0,
            saved_cursor: 0,
        }
    }
}

impl combinator::Parser<Token, ParseError> for Parser {
    fn consume(&mut self) -> Option<Token> {
        match self.input.get(self.cursor) {
            Some(token) => {
                self.cursor += 1;
                Some(token.clone())
            }
            None => None,
        }
    }

    fn preview(&self) -> Option<&Token> {
        self.input.get(self.cursor)
    }

    fn current_pos(&self) -> (i32, i32) {
        self.preview().unwrap().pos()
    }

    fn error<S: Into<String>>(&self, message: S) -> ParseError {
        ParseError {
            message: message.into(),
            token: if self.cursor > 0 {
                self.input.get(self.cursor - 1).map(|token| token.clone())
            } else {
                None
            },
        }
    }

    fn save(&mut self) {
        self.saved_cursor = self.cursor;
    }

    fn load(&mut self) {
        self.cursor = self.saved_cursor;
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 The Tink-Rust Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////

//! Testing server for keyset manipulation.

use crate::proto;
use tink_core::{utils::wrap_err, TinkError};
use tink_proto::prost::Message;

#[derive(Debug, Default)]
pub struct KeysetServerImpl;

#[tonic::async_trait]
impl proto::keyset_server::Keyset for KeysetServerImpl {
    async fn get_template(
        &self,
        _request: tonic::Request<proto::KeysetTemplateRequest>,
    ) -> Result<tonic::Response<proto::KeysetTemplateResponse>, tonic::Status> {
        // TODO: add implementation
        Err(tonic::Status::unimplemented("TODO"))
    }
    async fn generate(
        &self,
        request: tonic::Request<proto::KeysetGenerateRequest>,
    ) -> Result<tonic::Response<proto::KeysetGenerateResponse>, tonic::Status> {
        let req = request.into_inner(); // discard metadata
        let closure = move || -> Result<_, TinkError> {
            let template = tink_proto::KeyTemplate::decode(req.template.as_ref())
                .map_err(|e| wrap_err("decode failed", e))?;
            let handle = tink_core::keyset::Handle::new(&template)?;
            let mut buf = Vec::new();
            {
                let mut writer = tink_core::keyset::BinaryWriter::new(&mut buf);
                tink_core::keyset::insecure::write(&handle, &mut writer)
                    .map_err(|e| wrap_err("write failed", e))?;
            }
            Ok(buf)
        };
        Ok(tonic::Response::new(proto::KeysetGenerateResponse {
            result: Some(match closure() {
                Ok(buf) => proto::keyset_generate_response::Result::Keyset(buf),
                Err(e) => proto::keyset_generate_response::Result::Err(format!("{:?}", e)),
            }),
        }))
    }
    async fn public(
        &self,
        request: tonic::Request<proto::KeysetPublicRequest>,
    ) -> Result<tonic::Response<proto::KeysetPublicResponse>, tonic::Status> {
        let req = request.into_inner(); // discard metadata
        let closure = move || -> Result<_, TinkError> {
            let cursor = std::io::Cursor::new(req.private_keyset);
            let mut reader = tink_core::keyset::BinaryReader::new(cursor);
            let private_handle = tink_core::keyset::insecure::read(&mut reader)
                .map_err(|e| wrap_err("read failed", e))?;
            let public_handle = private_handle.public()?;
            let mut buf = Vec::new();
            {
                let mut writer = tink_core::keyset::BinaryWriter::new(&mut buf);
                tink_core::keyset::insecure::write(&public_handle, &mut writer)
                    .map_err(|e| wrap_err("write failed", e))?;
            }
            Ok(buf)
        };
        Ok(tonic::Response::new(proto::KeysetPublicResponse {
            result: Some(match closure() {
                Ok(buf) => proto::keyset_public_response::Result::PublicKeyset(buf),
                Err(e) => proto::keyset_public_response::Result::Err(format!("{:?}", e)),
            }),
        }))
    }
    async fn to_json(
        &self,
        request: tonic::Request<proto::KeysetToJsonRequest>,
    ) -> Result<tonic::Response<proto::KeysetToJsonResponse>, tonic::Status> {
        let req = request.into_inner(); // discard metadata
        let closure = move || -> Result<_, TinkError> {
            let cursor = std::io::Cursor::new(req.keyset);
            let mut reader = tink_core::keyset::BinaryReader::new(cursor);
            let handle = tink_core::keyset::insecure::read(&mut reader)
                .map_err(|e| wrap_err("read failed", e))?;
            let mut buf = Vec::new();
            {
                let mut writer = tink_core::keyset::JsonWriter::new(&mut buf);
                tink_core::keyset::insecure::write(&handle, &mut writer)
                    .map_err(|e| wrap_err("write failed", e))?;
            }
            let json = std::str::from_utf8(&buf).map_err(|e| wrap_err("utf8 failed", e))?;
            Ok(json.to_string())
        };
        Ok(tonic::Response::new(proto::KeysetToJsonResponse {
            result: Some(match closure() {
                Ok(json) => proto::keyset_to_json_response::Result::JsonKeyset(json),
                Err(e) => proto::keyset_to_json_response::Result::Err(format!("{:?}", e)),
            }),
        }))
    }
    async fn from_json(
        &self,
        request: tonic::Request<proto::KeysetFromJsonRequest>,
    ) -> Result<tonic::Response<proto::KeysetFromJsonResponse>, tonic::Status> {
        let req = request.into_inner(); // discard metadata
        let closure = move || -> Result<_, TinkError> {
            let cursor = std::io::Cursor::new(req.json_keyset.as_bytes());
            let mut reader = tink_core::keyset::JsonReader::new(cursor);
            let handle = tink_core::keyset::insecure::read(&mut reader)
                .map_err(|e| wrap_err("read failed", e))?;
            let mut buf = Vec::new();
            {
                let mut writer = tink_core::keyset::BinaryWriter::new(&mut buf);
                tink_core::keyset::insecure::write(&handle, &mut writer)
                    .map_err(|e| wrap_err("write failed", e))?;
            }
            Ok(buf)
        };
        Ok(tonic::Response::new(proto::KeysetFromJsonResponse {
            result: Some(match closure() {
                Ok(buf) => proto::keyset_from_json_response::Result::Keyset(buf),
                Err(e) => proto::keyset_from_json_response::Result::Err(format!("{:?}", e)),
            }),
        }))
    }
}
<commit_msg>tink-testing: implement get_template method<commit_after>// Copyright 2020 The Tink-Rust Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////

//! Testing server for keyset manipulation.

use crate::proto;
use tink_core::{utils::wrap_err, TinkError};
use tink_proto::prost::Message;

#[derive(Debug, Default)]
pub struct KeysetServerImpl;

#[tonic::async_trait]
impl proto::keyset_server::Keyset for KeysetServerImpl {
    async fn get_template(
        &self,
        request: tonic::Request<proto::KeysetTemplateRequest>,
    ) -> Result<tonic::Response<proto::KeysetTemplateResponse>, tonic::Status> {
        let req = request.into_inner(); // discard metadata
        let generator = tink_core::registry::get_template_generator(&req.template_name);
        Ok(tonic::Response::new(proto::KeysetTemplateResponse {
            result: Some(match generator {
                Some(f) => {
                    proto::keyset_template_response::Result::KeyTemplate(f().encode_to_vec())
                }
                None => proto::keyset_template_response::Result::Err(format!(
                    "key template {} not found",
                    req.template_name
                )),
            }),
        }))
    }
    async fn generate(
        &self,
        request: tonic::Request<proto::KeysetGenerateRequest>,
    ) -> Result<tonic::Response<proto::KeysetGenerateResponse>, tonic::Status> {
        let req = request.into_inner(); // discard metadata
        let closure = move || -> Result<_, TinkError> {
            let template = tink_proto::KeyTemplate::decode(req.template.as_ref())
                .map_err(|e| wrap_err("decode failed", e))?;
            let handle = tink_core::keyset::Handle::new(&template)?;
            let mut buf = Vec::new();
            {
                let mut writer = tink_core::keyset::BinaryWriter::new(&mut buf);
                tink_core::keyset::insecure::write(&handle, &mut writer)
                    .map_err(|e| wrap_err("write failed", e))?;
            }
            Ok(buf)
        };
        Ok(tonic::Response::new(proto::KeysetGenerateResponse {
            result: Some(match closure() {
                Ok(buf) => proto::keyset_generate_response::Result::Keyset(buf),
                Err(e) => proto::keyset_generate_response::Result::Err(format!("{:?}", e)),
            }),
        }))
    }
    async fn public(
        &self,
        request: tonic::Request<proto::KeysetPublicRequest>,
    ) -> Result<tonic::Response<proto::KeysetPublicResponse>, tonic::Status> {
        let req = request.into_inner(); // discard metadata
        let closure = move || -> Result<_, TinkError> {
            let cursor = std::io::Cursor::new(req.private_keyset);
            let mut reader = tink_core::keyset::BinaryReader::new(cursor);
            let private_handle = tink_core::keyset::insecure::read(&mut reader)
                .map_err(|e| wrap_err("read failed", e))?;
            let public_handle = private_handle.public()?;
            let mut buf = Vec::new();
            {
                let mut writer = tink_core::keyset::BinaryWriter::new(&mut buf);
                tink_core::keyset::insecure::write(&public_handle, &mut writer)
                    .map_err(|e| wrap_err("write failed", e))?;
            }
            Ok(buf)
        };
        Ok(tonic::Response::new(proto::KeysetPublicResponse {
            result: Some(match closure() {
                Ok(buf) => proto::keyset_public_response::Result::PublicKeyset(buf),
                Err(e) => proto::keyset_public_response::Result::Err(format!("{:?}", e)),
            }),
        }))
    }
    async fn to_json(
        &self,
        request: tonic::Request<proto::KeysetToJsonRequest>,
    ) -> Result<tonic::Response<proto::KeysetToJsonResponse>, tonic::Status> {
        let req = request.into_inner(); // discard metadata
        let closure = move || -> Result<_, TinkError> {
            let cursor = std::io::Cursor::new(req.keyset);
            let mut reader = tink_core::keyset::BinaryReader::new(cursor);
            let handle = tink_core::keyset::insecure::read(&mut reader)
                .map_err(|e| wrap_err("read failed", e))?;
            let mut buf = Vec::new();
            {
                let mut writer = tink_core::keyset::JsonWriter::new(&mut buf);
                tink_core::keyset::insecure::write(&handle, &mut writer)
                    .map_err(|e| wrap_err("write failed", e))?;
            }
            let json = std::str::from_utf8(&buf).map_err(|e| wrap_err("utf8 failed", e))?;
            Ok(json.to_string())
        };
        Ok(tonic::Response::new(proto::KeysetToJsonResponse {
            result: Some(match closure() {
                Ok(json) => proto::keyset_to_json_response::Result::JsonKeyset(json),
                Err(e) => proto::keyset_to_json_response::Result::Err(format!("{:?}", e)),
            }),
        }))
    }
    async fn from_json(
        &self,
        request: tonic::Request<proto::KeysetFromJsonRequest>,
    ) -> Result<tonic::Response<proto::KeysetFromJsonResponse>, tonic::Status> {
        let req = request.into_inner(); // discard metadata
        let closure = move || -> Result<_, TinkError> {
            let cursor = std::io::Cursor::new(req.json_keyset.as_bytes());
            let mut reader = tink_core::keyset::JsonReader::new(cursor);
            let handle = tink_core::keyset::insecure::read(&mut reader)
                .map_err(|e| wrap_err("read failed", e))?;
            let mut buf = Vec::new();
            {
                let mut writer = tink_core::keyset::BinaryWriter::new(&mut buf);
                tink_core::keyset::insecure::write(&handle, &mut writer)
                    .map_err(|e| wrap_err("write failed", e))?;
            }
            Ok(buf)
        };
        Ok(tonic::Response::new(proto::KeysetFromJsonResponse {
            result: Some(match closure() {
                Ok(buf) => proto::keyset_from_json_response::Result::Keyset(buf),
                Err(e) => proto::keyset_from_json_response::Result::Err(format!("{:?}", e)),
            }),
        }))
    }
}
<|endoftext|>


<commit_before>use hash::KEY_SIZE;
use hash::Hash160;
use std::net;
use std::cmp;
use std::collections::VecDeque;
use std::mem;

#[cfg(test)]
mod tests;

const K : usize = 20;
const BUCKET_DEPTH : usize = K;

/// Kademlia routing table, with 160 buckets of `BUCKET_DEPTH` (k) node
/// identifiers each.
///
/// The structure employs least-recently seen eviction. Conflicts generated
/// by evicting a node by inserting a newer one remain tracked, so they can
/// be resolved later.
pub struct RoutingTable {
   buckets        : Vec<Bucket>,
   conflicts      : Vec<EvictionConflict>,
}

/// Bucket size is estimated to be small enough not to warrant
/// the downsides of using a linked list.
#[derive(Debug, Clone)]
struct Bucket {
   entries  : VecDeque<NodeInfo>,
}

/// Represents a conflict derived from attempting to insert a node in a full
/// bucket.
#[derive(Debug,Clone)]
struct EvictionConflict {
   evicted  : NodeInfo,
   inserted : NodeInfo
}

#[derive(Debug, Clone, PartialEq)]
pub struct NodeInfo {
   pub node_id : Hash160,
   pub ip      : Option<net::IpAddr>,
   pub port    : Option<u16>,
}

#[derive(Debug, PartialEq)]
pub enum LookupResult {
   Found(NodeInfo),
   ClosestNodes(Vec<NodeInfo>),
}

impl RoutingTable {
   pub fn new(parent_node_id : Hash160) -> RoutingTable {
      let mut buckets = Vec::<Bucket>::with_capacity(KEY_SIZE);
      for i in 0..KEY_SIZE {
         buckets.push(Bucket::for_distances(i));
      }

      let mut table = RoutingTable {
         buckets : buckets,
         conflicts  : Vec::new()
      };

      // Store the parent node at entry zero.
      table.buckets[0].entries.push_back( NodeInfo {
         node_id : parent_node_id,
         ip  : None,
         port : None
      });
      table
   }

   /// Inserts a node in the routing table. Employs least-recently-seen eviction
   /// by kicking out the oldest node in case the bucket is full, and registering
   /// an eviction conflict that can be revised later.
   pub fn insert_node(&mut self, info : NodeInfo) {
      let index = self.bucket_for_node(&info.node_id);
      let bucket = &mut self.buckets[index];
      bucket.entries.retain(|ref stored_info| info.node_id != stored_info.node_id);
      if bucket.entries.len() == BUCKET_DEPTH {
         let conflict = EvictionConflict {
            evicted  : bucket.entries.pop_front().unwrap(),
            inserted : info.clone()
         };
         self.conflicts.push(conflict);
      }
      bucket.entries.push_back(info);
   }

   /// Performs a node lookup on the routing table. The lookup result may
   /// contain the specific node, a list of up to the N closest nodes, or
   /// report that the parent node itself was requested.
   pub fn lookup(&self, node_id : &Hash160, n : usize) -> LookupResult {
      match self.specific_node(node_id) {
         Some(info) => LookupResult::Found(info),
         None => LookupResult::ClosestNodes(self.closest_n_nodes_to(node_id, n)),
      }
   }

   /// Returns a table entry for the specific node with a given hash.
   fn specific_node(&self, node_id : &Hash160) -> Option<NodeInfo> {
      let index = self.bucket_for_node(node_id);
      let bucket = &self.buckets[index];
      bucket.entries.iter().find(|ref info| *node_id == info.node_id).cloned()
   }

   fn closest_n_nodes_to(&self, node_id : &Hash160, n : usize) -> Vec<NodeInfo> {
      let mut closest = Vec::with_capacity(n);
      let parent_node_id = &self.buckets[0].entries[0].node_id;
      let distance = parent_node_id ^ node_id;
      let descent  = distance.clone().ones().rev();
      let ascent   = distance.clone().zeroes();
      let lookup_order = descent.chain(ascent);

      for bucket_index in lookup_order {
         if self.buckets[bucket_index].entries.is_empty() {
            continue;
         }

         let mut nodes_from_bucket = self.buckets[bucket_index].entries.clone().into_iter().collect::<Vec<NodeInfo>>();
         println!("Trying bucket {} with {} entries", bucket_index, nodes_from_bucket.len());
         nodes_from_bucket.sort_by_key(|ref info| &info.node_id ^ node_id);
         let space_left = closest.capacity() - closest.len();
         nodes_from_bucket.truncate(space_left);
         closest.append(&mut nodes_from_bucket);

         if closest.len() == closest.capacity() {
            break;
         }
      }
      closest
   }

   /// Returns the appropriate position for a node, by computing
   /// the last bit of their distance set to 1. If we are requesting
   /// the bucket for this table's own parent node, we offer bucket 0.
   fn bucket_for_node(&self, node_id : &Hash160) -> usize {
      let parent_node_id = &self.buckets[0].entries[0].node_id;
       match (parent_node_id ^ node_id).height() {
          Some(bucket) => bucket,
          None => 0
       }
   }

   fn revert_conflict(&mut self, conflict : EvictionConflict) {
      let index = self.bucket_for_node(&conflict.inserted.node_id);
      let bucket  = &mut self.buckets[index];
      let evictor = &mut bucket.entries.iter_mut().find(|ref info| conflict.inserted.node_id == info.node_id).unwrap();
      mem::replace::<NodeInfo>(evictor, conflict.evicted);
   }
}

impl Bucket {
   pub fn for_distances(distance : usize) -> Bucket {
      Bucket { entries : VecDeque::<NodeInfo>::with_capacity(cmp::min(2^distance, BUCKET_DEPTH)) }
   }
}
<commit_msg>Refactoring<commit_after>use hash::KEY_SIZE;
use hash::Hash160;
use std::net;
use std::cmp;
use std::collections::VecDeque;
use std::mem;

#[cfg(test)]
mod tests;

const K : usize = 20;
const BUCKET_DEPTH : usize = K;

/// Kademlia routing table, with 160 buckets of `BUCKET_DEPTH` (k) node
/// identifiers each.
///
/// The structure employs least-recently seen eviction. Conflicts generated
/// by evicting a node by inserting a newer one remain tracked, so they can
/// be resolved later.
pub struct RoutingTable {
   buckets        : Vec<Bucket>,
   conflicts      : Vec<EvictionConflict>,
}

/// Bucket size is estimated to be small enough not to warrant
/// the downsides of using a linked list.
#[derive(Debug, Clone)]
struct Bucket {
   entries  : VecDeque<NodeInfo>,
}

/// Represents a conflict derived from attempting to insert a node in a full
/// bucket.
#[derive(Debug,Clone)]
struct EvictionConflict {
   evicted  : NodeInfo,
   inserted : NodeInfo
}

#[derive(Debug, Clone, PartialEq)]
pub struct NodeInfo {
   pub node_id : Hash160,
   pub ip      : Option<net::IpAddr>,
   pub port    : Option<u16>,
}

#[derive(Debug, PartialEq)]
pub enum LookupResult {
   Found(NodeInfo),
   ClosestNodes(Vec<NodeInfo>),
}

impl RoutingTable {
   pub fn new(parent_node_id : Hash160) -> RoutingTable {
      let mut buckets = Vec::<Bucket>::with_capacity(KEY_SIZE);
      for i in 0..KEY_SIZE {
         buckets.push(Bucket::for_distances(i));
      }

      let mut table = RoutingTable {
         buckets : buckets,
         conflicts  : Vec::new()
      };

      // Store the parent node at entry zero.
      table.buckets[0].entries.push_back( NodeInfo {
         node_id : parent_node_id,
         ip  : None,
         port : None
      });
      table
   }

   /// Inserts a node in the routing table. Employs least-recently-seen eviction
   /// by kicking out the oldest node in case the bucket is full, and registering
   /// an eviction conflict that can be revised later.
   pub fn insert_node(&mut self, info : NodeInfo) {
      let index = self.bucket_for_node(&info.node_id);
      let bucket = &mut self.buckets[index];
      bucket.entries.retain(|ref stored_info| info.node_id != stored_info.node_id);
      if bucket.entries.len() == BUCKET_DEPTH {
         let conflict = EvictionConflict {
            evicted  : bucket.entries.pop_front().unwrap(),
            inserted : info.clone()
         };
         self.conflicts.push(conflict);
      }
      bucket.entries.push_back(info);
   }

   /// Performs a node lookup on the routing table. The lookup result may
   /// contain the specific node, a list of up to the N closest nodes, or
   /// report that the parent node itself was requested.
   pub fn lookup(&self, node_id : &Hash160, n : usize) -> LookupResult {
      match self.specific_node(node_id) {
         Some(info) => LookupResult::Found(info),
         None => LookupResult::ClosestNodes(self.closest_n_nodes_to(node_id, n)),
      }
   }

   /// Returns a table entry for the specific node with a given hash.
   fn specific_node(&self, node_id : &Hash160) -> Option<NodeInfo> {
      let index = self.bucket_for_node(node_id);
      let bucket = &self.buckets[index];
      bucket.entries.iter().find(|ref info| *node_id == info.node_id).cloned()
   }

   fn closest_n_nodes_to(&self, node_id : &Hash160, n : usize) -> Vec<NodeInfo> {
      let mut closest = Vec::with_capacity(n);
      let parent_node_id = &self.buckets[0].entries[0].node_id;
      let distance = parent_node_id ^ node_id;
      let descent  = distance.clone().ones().rev();
      let ascent   = distance.clone().zeroes();
      let lookup_order = descent.chain(ascent);

      for bucket_index in lookup_order {
         if self.buckets[bucket_index].entries.is_empty() {
            continue;
         }

         let mut nodes_from_bucket = self.buckets[bucket_index].entries.clone().into_iter().collect::<Vec<NodeInfo>>();
         println!("Trying bucket {} with {} entries", bucket_index, nodes_from_bucket.len());
         nodes_from_bucket.sort_by_key(|ref info| &info.node_id ^ node_id);
         let space_left = closest.capacity() - closest.len();
         nodes_from_bucket.truncate(space_left);
         closest.append(&mut nodes_from_bucket);

         if closest.len() == closest.capacity() {
            break;
         }
      }
      closest
   }

   /// Returns the appropriate position for a node, by computing
   /// the index where their prefix starts differing. If we are requesting
   /// the bucket for this table's own parent node, we point at bucket 0.
   fn bucket_for_node(&self, node_id : &Hash160) -> usize {
      let parent_node_id = &self.buckets[0].entries[0].node_id;
       match (parent_node_id ^ node_id).height() {
          Some(bucket) => bucket,
          None => 0
       }
   }

   fn revert_conflict(&mut self, conflict : EvictionConflict) {
      let index = self.bucket_for_node(&conflict.inserted.node_id);
      let bucket  = &mut self.buckets[index];
      let evictor = &mut bucket.entries.iter_mut().find(|ref info| conflict.inserted.node_id == info.node_id).unwrap();
      mem::replace::<NodeInfo>(evictor, conflict.evicted);
   }
}

impl Bucket {
   pub fn for_distances(distance : usize) -> Bucket {
      Bucket { entries : VecDeque::<NodeInfo>::with_capacity(cmp::min(2^distance, BUCKET_DEPTH)) }
   }
}
<|endoftext|>