<commit_before>use rustc_errors::Applicability;
use rustc_hir::{
    intravisit::{walk_expr, NestedVisitorMap, Visitor},
    Expr, ExprKind,
};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
use rustc_span::source_map::Span;

use if_chain::if_chain;

use crate::utils::{has_iter_method, match_trait_method, paths, snippet, span_lint_and_then};

use super::EXCESSIVE_FOR_EACH;

pub(super) fn lint(cx: &LateContext<'_>, expr: &'tcx Expr<'_>, args: &[&[Expr<'_>]]) {
    if args.len() < 2 {
        return;
    }

    let for_each_args = args[0];
    if for_each_args.len() < 2 {
        return;
    }
    let for_each_receiver = &for_each_args[0];
    let for_each_arg = &for_each_args[1];
    let iter_receiver = &args[1][0];

    if_chain! {
        if has_iter_method(cx, cx.typeck_results().expr_ty(iter_receiver)).is_some();
        if match_trait_method(cx, expr, &paths::ITERATOR);
        if let ExprKind::Closure(_, _, body_id, ..) = for_each_arg.kind;
        let body = cx.tcx.hir().body(body_id);
        if let ExprKind::Block(..) = body.value.kind;
        then {
            let mut ret_collector = RetCollector::new();
            ret_collector.visit_expr(&body.value);

            // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`.
            if ret_collector.ret_in_loop {
                return;
            }

            let sugg = format!(
                "for {} in {} {{ .. }}",
                snippet(cx, body.params[0].pat.span, ""),
                snippet(cx, for_each_receiver.span, "")
            );

            span_lint_and_then(
                cx,
                EXCESSIVE_FOR_EACH,
                expr.span,
                "excessive use of `for_each`",
                |diag| {
                    diag.span_suggestion(expr.span, "try", sugg, Applicability::HasPlaceholders);
                    for span in ret_collector.spans {
                        diag.span_note(span, "change `return` to `continue` in the loop body");
                    }
                }
            )
        }
    }
}

/// This type plays two roles.
/// 1. Collect spans of `return` in the closure body.
/// 2. Detect use of `return` in `Loop` in the closure body.
///
/// NOTE: The functionality of this type is similar to
/// [`crate::utilts::visitors::find_all_ret_expressions`], but we can't use
/// `find_all_ret_expressions` instead of this type. The reasons are:
/// 1. `find_all_ret_expressions` passes the argument of `ExprKind::Ret` to a callback, but what we
///    need here is `ExprKind::Ret` itself.
/// 2. We can't trace current loop depth with `find_all_ret_expressions`.
struct RetCollector {
    spans: Vec<Span>,
    ret_in_loop: bool,

    loop_depth: u16,
}

impl RetCollector {
    fn new() -> Self {
        Self {
            spans: Vec::new(),
            ret_in_loop: false,
            loop_depth: 0,
        }
    }
}

impl<'tcx> Visitor<'tcx> for RetCollector {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &Expr<'_>) {
        match expr.kind {
            ExprKind::Ret(..) => {
                if self.loop_depth > 0 && !self.ret_in_loop {
                    self.ret_in_loop = true
                }

                self.spans.push(expr.span)
            },

            ExprKind::Loop(..) => {
                self.loop_depth += 1;
                walk_expr(self, expr);
                self.loop_depth -= 1;
                return;
            },

            _ => {},
        }

        walk_expr(self, expr);
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}
<commit_msg>Use ".." as default value of snippet in excessive_for_each<commit_after>use rustc_errors::Applicability;
use rustc_hir::{
    intravisit::{walk_expr, NestedVisitorMap, Visitor},
    Expr, ExprKind,
};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
use rustc_span::source_map::Span;

use if_chain::if_chain;

use crate::utils::{has_iter_method, match_trait_method, paths, snippet, span_lint_and_then};

use super::EXCESSIVE_FOR_EACH;

pub(super) fn lint(cx: &LateContext<'_>, expr: &'tcx Expr<'_>, args: &[&[Expr<'_>]]) {
    if args.len() < 2 {
        return;
    }

    let for_each_args = args[0];
    if for_each_args.len() < 2 {
        return;
    }
    let for_each_receiver = &for_each_args[0];
    let for_each_arg = &for_each_args[1];
    let iter_receiver = &args[1][0];

    if_chain! {
        if has_iter_method(cx, cx.typeck_results().expr_ty(iter_receiver)).is_some();
        if match_trait_method(cx, expr, &paths::ITERATOR);
        if let ExprKind::Closure(_, _, body_id, ..) = for_each_arg.kind;
        let body = cx.tcx.hir().body(body_id);
        if let ExprKind::Block(..) = body.value.kind;
        then {
            let mut ret_collector = RetCollector::new();
            ret_collector.visit_expr(&body.value);

            // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`.
            if ret_collector.ret_in_loop {
                return;
            }

            let sugg = format!(
                "for {} in {} {{ .. }}",
                snippet(cx, body.params[0].pat.span, ".."),
                snippet(cx, for_each_receiver.span, "..")
            );

            span_lint_and_then(
                cx,
                EXCESSIVE_FOR_EACH,
                expr.span,
                "excessive use of `for_each`",
                |diag| {
                    diag.span_suggestion(expr.span, "try", sugg, Applicability::HasPlaceholders);
                    for span in ret_collector.spans {
                        diag.span_note(span, "change `return` to `continue` in the loop body");
                    }
                }
            )
        }
    }
}

/// This type plays two roles.
/// 1. Collect spans of `return` in the closure body.
/// 2. Detect use of `return` in `Loop` in the closure body.
///
/// NOTE: The functionality of this type is similar to
/// [`crate::utilts::visitors::find_all_ret_expressions`], but we can't use
/// `find_all_ret_expressions` instead of this type. The reasons are:
/// 1. `find_all_ret_expressions` passes the argument of `ExprKind::Ret` to a callback, but what we
///    need here is `ExprKind::Ret` itself.
/// 2. We can't trace current loop depth with `find_all_ret_expressions`.
struct RetCollector {
    spans: Vec<Span>,
    ret_in_loop: bool,

    loop_depth: u16,
}

impl RetCollector {
    fn new() -> Self {
        Self {
            spans: Vec::new(),
            ret_in_loop: false,
            loop_depth: 0,
        }
    }
}

impl<'tcx> Visitor<'tcx> for RetCollector {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &Expr<'_>) {
        match expr.kind {
            ExprKind::Ret(..) => {
                if self.loop_depth > 0 && !self.ret_in_loop {
                    self.ret_in_loop = true
                }

                self.spans.push(expr.span)
            },

            ExprKind::Loop(..) => {
                self.loop_depth += 1;
                walk_expr(self, expr);
                self.loop_depth -= 1;
                return;
            },

            _ => {},
        }

        walk_expr(self, expr);
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}
<|endoftext|>


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

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 * (c) Vsevolod Velichko <torkvemada@sorokdva.net>
 * (c) Gil Cottle <gcottle@redtown.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]

extern crate regex;

extern crate crypto = "rust-crypto";
extern crate getopts;

use std::io::fs::File;
use std::io::stdio::stdin_raw;
use std::io::BufferedReader;
use std::io::IoError;
use std::io::EndOfFile;
use regex::Regex;
use crypto::digest::Digest;
use crypto::md5::Md5;
use crypto::sha1::Sha1;
use crypto::sha2::{Sha224, Sha256, Sha384, Sha512};

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

static NAME: &'static str = "hashsum";
static VERSION: &'static str = "1.0.0";

fn is_custom_binary(program: &str) -> bool {
    match program {
        "md5sum" | "sha1sum"
            | "sha224sum" | "sha256sum"
            | "sha384sum" | "sha512sum" => true,
        _ => false
    }
}

fn get_algo_opts(program: &str) -> Vec<getopts::OptGroup> {
    if is_custom_binary(program) {
        Vec::new()
    } else {
        vec!(
            getopts::optflag("", "md5", "work with MD5"),
            getopts::optflag("", "sha1", "work with SHA1"),
            getopts::optflag("", "sha224", "work with SHA224"),
            getopts::optflag("", "sha256", "work with SHA256"),
            getopts::optflag("", "sha384", "work with SHA384"),
            getopts::optflag("", "sha512", "work with SHA512")
        )
    }
}

fn detect_algo(program: &str, matches: &getopts::Matches) -> (&str, Box<Digest>) {
    let mut alg: Option<Box<Digest>> = None;
    let mut name: &'static str = "";
    match program {
        "md5sum" => ("MD5", box Md5::new() as Box<Digest>),
        "sha1sum" => ("SHA1", box Sha1::new() as Box<Digest>),
        "sha224sum" => ("SHA224", box Sha224::new() as Box<Digest>),
        "sha256sum" => ("SHA256", box Sha256::new() as Box<Digest>),
        "sha384sum" => ("SHA384", box Sha384::new() as Box<Digest>),
        "sha512sum" => ("SHA512", box Sha512::new() as Box<Digest>),
        _ => {
            {
                let set_or_crash = |n: &'static str, val: Box<Digest>| -> () {
                    if alg.is_some() { crash!(1, "You cannot combine multiple hash algorithms!") };
                    name = n;
                    alg = Some(val);
                };
                if matches.opt_present("md5") { set_or_crash("MD5", box Md5::new()) };
                if matches.opt_present("sha1") { set_or_crash("SHA1", box Sha1::new()) };
                if matches.opt_present("sha224") { set_or_crash("SHA224", box Sha224::new()) };
                if matches.opt_present("sha256") { set_or_crash("SHA256", box Sha256::new()) };
                if matches.opt_present("sha384") { set_or_crash("SHA384", box Sha384::new()) };
                if matches.opt_present("sha512") { set_or_crash("SHA512", box Sha512::new()) };
            }
            if alg.is_none() { crash!(1, "You must specify hash algorithm!") };
            (name, alg.unwrap())
        }
    }
}

pub fn uumain(args: Vec<String>) -> int {
    let program = args[0].clone();
    let binary = Path::new(program.as_slice());
    let binary_name = binary.filename_str().unwrap();

    // Default binary in Windows, text mode otherwise
    let binary_flag_default = cfg!(windows);

    let mut opts: Vec<getopts::OptGroup> = vec!(
        getopts::optflag("b", "binary", format!("read in binary mode{}", if binary_flag_default { " (default)" } else { "" }).as_slice()),
        getopts::optflag("c", "check", "read hashsums from the FILEs and check them"),
        getopts::optflag("", "tag", "create a BSD-style checksum"),
        getopts::optflag("t", "text", format!("read in text mode{}", if binary_flag_default { "" } else { " (default)" }).as_slice()),
        getopts::optflag("q", "quiet", "don't print OK for each successfully verified file"),
        getopts::optflag("s", "status", "don't output anything, status code shows success"),
        getopts::optflag("", "strict", "exit non-zero for improperly formatted checksum lines"),
        getopts::optflag("w", "warn", "warn about improperly formatted checksum lines"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    );

    opts.push_all_move(get_algo_opts(binary_name.as_slice()));

    let matches = match getopts::getopts(args.tail(), opts.as_slice()) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f)
    };

    if matches.opt_present("help") {
        usage(program.as_slice(), binary_name.as_slice(), opts.as_slice());
    } else if matches.opt_present("version") {
        version();
    } else {
        let (name, algo) = detect_algo(binary_name.as_slice(), &matches);

        let binary_flag = matches.opt_present("binary");
        let text_flag = matches.opt_present("text");
        if binary_flag && text_flag {
            crash!(1, "cannot set binary and text mode at the same time");
        }
        let binary = if binary_flag { true } else if text_flag { false } else { binary_flag_default };
        let check = matches.opt_present("check");
        let tag = matches.opt_present("tag");
        let status = matches.opt_present("status");
        let quiet = matches.opt_present("quiet") || status;
        let strict = matches.opt_present("strict");
        let warn = matches.opt_present("warn") && !status;
        let files = if matches.free.is_empty() {
            vec!("-".to_string())
        } else {
            matches.free
        };
        match hashsum(name, algo, files, binary, check, tag, status, quiet, strict, warn) {
            Ok(()) => return 0,
            Err(e) => return e
        }
    }

    0
}

fn version() {
    println!("{} v{}", NAME, VERSION);
}

fn usage(program: &str, binary_name: &str, opts: &[getopts::OptGroup]) {
    version();
    println!("");
    println!("Usage:");
    if is_custom_binary(binary_name) {
        println!("  {} [OPTION]... [FILE]...", program);
    } else {
        println!("  {} {{--md5|--sha1|--sha224|--sha256|--sha384|--sha512}} [OPTION]... [FILE]...", program);
    }
    println!("");
    print!("{}", getopts::usage("Compute and check message digests.", opts));
}

fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary: bool, check: bool, tag: bool, status: bool, quiet: bool, strict: bool, warn: bool) -> Result<(), int> {
    let mut bad_format = 0u;
    let mut failed = 0u;
    let binary_marker = if binary {
        "*"
    } else {
        " "
    };
    for filename in files.iter() {
        let filename: &str = filename.as_slice();
        let mut file = BufferedReader::new(
            if filename == "-" {
                box stdin_raw() as Box<Reader>
            } else {
                box safe_unwrap!(File::open(&Path::new(filename))) as Box<Reader>
            }
        );
        if check {

            // Set up Regexes for line validation and parsing
            let bytes = digest.output_bits() / 4;
            let gnu_re = safe_unwrap!(
                Regex::new(
                    format!(
                        r"^(?P<digest>[a-fA-F0-9]{{{}}}) (?P<binary>[ \*])(?P<fileName>.*)",
                        bytes
                    ).as_slice()
                )
            );
            let bsd_re = safe_unwrap!(
                Regex::new(
                    format!(
                        r"^{algorithm} \((?P<fileName>.*)\) = (?P<digest>[a-fA-F0-9]{{{digest_size}}})",
                        algorithm = algoname,
                        digest_size = bytes
                    ).as_slice()
                )
            );

            let mut buffer = file;
            for (i, line) in buffer.lines().enumerate() {
                let line = safe_unwrap!(line);
                let (ck_filename, sum, binary_check) = match gnu_re.captures(line.as_slice()) {
                    Some(caps) => (caps.name("fileName"), caps.name("digest").to_ascii().to_lower(), caps.name("binary") == "*"),
                    None => match bsd_re.captures(line.as_slice()) {
                        Some(caps) => (caps.name("fileName"), caps.name("digest").to_ascii().to_lower(), true),
                        None => {
                            bad_format += 1;
                            if strict {
                                return Err(1);
                            }
                            if warn {
                                show_warning!("{}: {}: improperly formatted {} checksum line", filename, i + 1, algoname);
                            }
                            continue;
                        }
                    }
                };
                let real_sum = safe_unwrap!(digest_reader(&mut digest, &mut safe_unwrap!(File::open(&Path::new(ck_filename))), binary_check))
                    .as_slice().to_ascii().to_lower();
                if sum.as_slice() == real_sum.as_slice() {
                    if !quiet {
                        println!("{}: OK", ck_filename);
                    }
                } else {
                    if !status {
                        println!("{}: FAILED", ck_filename);
                    }
                    failed += 1;
                }
            }
        } else {
            let sum = safe_unwrap!(digest_reader(&mut digest, &mut file, binary));
            if tag {
                println!("{} ({}) = {}", algoname, filename, sum);
            } else {
                println!("{} {}{}", sum, binary_marker, filename);
            }
        }
    }
    if !status {
        if bad_format == 1 {
            show_warning!("{} line is improperly formatted", bad_format);
        } else if bad_format > 1 {
            show_warning!("{} lines are improperly formatted", bad_format);
        }
        if failed > 0 {
            show_warning!("{} computed checksum did NOT match", failed);
        }
    }

    Ok(())
}

fn digest_reader(digest: &mut Box<Digest>, reader: &mut Reader, binary: bool) -> Result<String, IoError> {
    digest.reset();

    // Digest file, do not hold too much in memory at any given moment
    let windows = cfg!(windows);
    let mut buffer = [0, ..524288];
    let mut vec = Vec::with_capacity(524288);
    let mut looking_for_newline = false;
    loop {
        match reader.read(buffer) {
            Ok(0) => {},
            Ok(nread) => {
                if windows && !binary {
                    // Windows text mode returns '\n' when reading '\r\n'
                    for i in range(0, nread) {
                        if looking_for_newline {
                            if buffer[i] != ('\n' as u8) {
                                vec.push('\r' as u8);
                            }
                            if buffer[i] != ('\r' as u8) {
                                vec.push(buffer[i]);
                                looking_for_newline = false;
                            }
                        } else if buffer[i] != ('\r' as u8) {
                            vec.push(buffer[i]);
                        } else {
                            looking_for_newline = true;
                        }
                    }
                    digest.input(vec.as_slice());
                    vec.clear();
                } else {
                    digest.input(buffer.slice(0, nread));
                }
            },
            Err(e) => match e.kind {
                EndOfFile => {
                    break;
                },
                _ => {
                    return Err(e);
                }
            }
        }
    }
    if windows && looking_for_newline {
        vec.push('\r' as u8);
        digest.input(vec.as_slice());
    }

    Ok(digest.result_str())
}
<commit_msg>hashsum: fix build<commit_after>#![crate_name = "hashsum"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 * (c) Vsevolod Velichko <torkvemada@sorokdva.net>
 * (c) Gil Cottle <gcottle@redtown.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]

extern crate regex;

extern crate crypto = "rust-crypto";
extern crate getopts;

use std::io::fs::File;
use std::io::stdio::stdin_raw;
use std::io::BufferedReader;
use std::io::IoError;
use std::io::EndOfFile;
use regex::Regex;
use crypto::digest::Digest;
use crypto::md5::Md5;
use crypto::sha1::Sha1;
use crypto::sha2::{Sha224, Sha256, Sha384, Sha512};

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

static NAME: &'static str = "hashsum";
static VERSION: &'static str = "1.0.0";

fn is_custom_binary(program: &str) -> bool {
    match program {
        "md5sum" | "sha1sum"
            | "sha224sum" | "sha256sum"
            | "sha384sum" | "sha512sum" => true,
        _ => false
    }
}

fn get_algo_opts(program: &str) -> Vec<getopts::OptGroup> {
    if is_custom_binary(program) {
        Vec::new()
    } else {
        vec!(
            getopts::optflag("", "md5", "work with MD5"),
            getopts::optflag("", "sha1", "work with SHA1"),
            getopts::optflag("", "sha224", "work with SHA224"),
            getopts::optflag("", "sha256", "work with SHA256"),
            getopts::optflag("", "sha384", "work with SHA384"),
            getopts::optflag("", "sha512", "work with SHA512")
        )
    }
}

fn detect_algo(program: &str, matches: &getopts::Matches) -> (&'static str, Box<Digest>) {
    let mut alg: Option<Box<Digest>> = None;
    let mut name: &'static str = "";
    match program {
        "md5sum" => ("MD5", box Md5::new() as Box<Digest>),
        "sha1sum" => ("SHA1", box Sha1::new() as Box<Digest>),
        "sha224sum" => ("SHA224", box Sha224::new() as Box<Digest>),
        "sha256sum" => ("SHA256", box Sha256::new() as Box<Digest>),
        "sha384sum" => ("SHA384", box Sha384::new() as Box<Digest>),
        "sha512sum" => ("SHA512", box Sha512::new() as Box<Digest>),
        _ => {
            {
                let set_or_crash = |n: &'static str, val: Box<Digest>| -> () {
                    if alg.is_some() { crash!(1, "You cannot combine multiple hash algorithms!") };
                    name = n;
                    alg = Some(val);
                };
                if matches.opt_present("md5") { set_or_crash("MD5", box Md5::new()) };
                if matches.opt_present("sha1") { set_or_crash("SHA1", box Sha1::new()) };
                if matches.opt_present("sha224") { set_or_crash("SHA224", box Sha224::new()) };
                if matches.opt_present("sha256") { set_or_crash("SHA256", box Sha256::new()) };
                if matches.opt_present("sha384") { set_or_crash("SHA384", box Sha384::new()) };
                if matches.opt_present("sha512") { set_or_crash("SHA512", box Sha512::new()) };
            }
            if alg.is_none() { crash!(1, "You must specify hash algorithm!") };
            (name, alg.unwrap())
        }
    }
}

pub fn uumain(args: Vec<String>) -> int {
    let program = args[0].clone();
    let binary = Path::new(program.as_slice());
    let binary_name = binary.filename_str().unwrap();

    // Default binary in Windows, text mode otherwise
    let binary_flag_default = cfg!(windows);

    let mut opts: Vec<getopts::OptGroup> = vec!(
        getopts::optflag("b", "binary", format!("read in binary mode{}", if binary_flag_default { " (default)" } else { "" }).as_slice()),
        getopts::optflag("c", "check", "read hashsums from the FILEs and check them"),
        getopts::optflag("", "tag", "create a BSD-style checksum"),
        getopts::optflag("t", "text", format!("read in text mode{}", if binary_flag_default { "" } else { " (default)" }).as_slice()),
        getopts::optflag("q", "quiet", "don't print OK for each successfully verified file"),
        getopts::optflag("s", "status", "don't output anything, status code shows success"),
        getopts::optflag("", "strict", "exit non-zero for improperly formatted checksum lines"),
        getopts::optflag("w", "warn", "warn about improperly formatted checksum lines"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    );

    opts.push_all_move(get_algo_opts(binary_name.as_slice()));

    let matches = match getopts::getopts(args.tail(), opts.as_slice()) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f)
    };

    if matches.opt_present("help") {
        usage(program.as_slice(), binary_name.as_slice(), opts.as_slice());
    } else if matches.opt_present("version") {
        version();
    } else {
        let (name, algo) = detect_algo(binary_name.as_slice(), &matches);

        let binary_flag = matches.opt_present("binary");
        let text_flag = matches.opt_present("text");
        if binary_flag && text_flag {
            crash!(1, "cannot set binary and text mode at the same time");
        }
        let binary = if binary_flag { true } else if text_flag { false } else { binary_flag_default };
        let check = matches.opt_present("check");
        let tag = matches.opt_present("tag");
        let status = matches.opt_present("status");
        let quiet = matches.opt_present("quiet") || status;
        let strict = matches.opt_present("strict");
        let warn = matches.opt_present("warn") && !status;
        let files = if matches.free.is_empty() {
            vec!("-".to_string())
        } else {
            matches.free
        };
        match hashsum(name, algo, files, binary, check, tag, status, quiet, strict, warn) {
            Ok(()) => return 0,
            Err(e) => return e
        }
    }

    0
}

fn version() {
    println!("{} v{}", NAME, VERSION);
}

fn usage(program: &str, binary_name: &str, opts: &[getopts::OptGroup]) {
    version();
    println!("");
    println!("Usage:");
    if is_custom_binary(binary_name) {
        println!("  {} [OPTION]... [FILE]...", program);
    } else {
        println!("  {} {{--md5|--sha1|--sha224|--sha256|--sha384|--sha512}} [OPTION]... [FILE]...", program);
    }
    println!("");
    print!("{}", getopts::usage("Compute and check message digests.", opts));
}

fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary: bool, check: bool, tag: bool, status: bool, quiet: bool, strict: bool, warn: bool) -> Result<(), int> {
    let mut bad_format = 0u;
    let mut failed = 0u;
    let binary_marker = if binary {
        "*"
    } else {
        " "
    };
    for filename in files.iter() {
        let filename: &str = filename.as_slice();
        let mut file = BufferedReader::new(
            if filename == "-" {
                box stdin_raw() as Box<Reader>
            } else {
                box safe_unwrap!(File::open(&Path::new(filename))) as Box<Reader>
            }
        );
        if check {

            // Set up Regexes for line validation and parsing
            let bytes = digest.output_bits() / 4;
            let gnu_re = safe_unwrap!(
                Regex::new(
                    format!(
                        r"^(?P<digest>[a-fA-F0-9]{{{}}}) (?P<binary>[ \*])(?P<fileName>.*)",
                        bytes
                    ).as_slice()
                )
            );
            let bsd_re = safe_unwrap!(
                Regex::new(
                    format!(
                        r"^{algorithm} \((?P<fileName>.*)\) = (?P<digest>[a-fA-F0-9]{{{digest_size}}})",
                        algorithm = algoname,
                        digest_size = bytes
                    ).as_slice()
                )
            );

            let mut buffer = file;
            for (i, line) in buffer.lines().enumerate() {
                let line = safe_unwrap!(line);
                let (ck_filename, sum, binary_check) = match gnu_re.captures(line.as_slice()) {
                    Some(caps) => (caps.name("fileName"), caps.name("digest").to_ascii().to_lower(), caps.name("binary") == "*"),
                    None => match bsd_re.captures(line.as_slice()) {
                        Some(caps) => (caps.name("fileName"), caps.name("digest").to_ascii().to_lower(), true),
                        None => {
                            bad_format += 1;
                            if strict {
                                return Err(1);
                            }
                            if warn {
                                show_warning!("{}: {}: improperly formatted {} checksum line", filename, i + 1, algoname);
                            }
                            continue;
                        }
                    }
                };
                let real_sum = safe_unwrap!(digest_reader(&mut digest, &mut safe_unwrap!(File::open(&Path::new(ck_filename))), binary_check))
                    .as_slice().to_ascii().to_lower();
                if sum.as_slice() == real_sum.as_slice() {
                    if !quiet {
                        println!("{}: OK", ck_filename);
                    }
                } else {
                    if !status {
                        println!("{}: FAILED", ck_filename);
                    }
                    failed += 1;
                }
            }
        } else {
            let sum = safe_unwrap!(digest_reader(&mut digest, &mut file, binary));
            if tag {
                println!("{} ({}) = {}", algoname, filename, sum);
            } else {
                println!("{} {}{}", sum, binary_marker, filename);
            }
        }
    }
    if !status {
        if bad_format == 1 {
            show_warning!("{} line is improperly formatted", bad_format);
        } else if bad_format > 1 {
            show_warning!("{} lines are improperly formatted", bad_format);
        }
        if failed > 0 {
            show_warning!("{} computed checksum did NOT match", failed);
        }
    }

    Ok(())
}

fn digest_reader(digest: &mut Box<Digest>, reader: &mut Reader, binary: bool) -> Result<String, IoError> {
    digest.reset();

    // Digest file, do not hold too much in memory at any given moment
    let windows = cfg!(windows);
    let mut buffer = [0, ..524288];
    let mut vec = Vec::with_capacity(524288);
    let mut looking_for_newline = false;
    loop {
        match reader.read(buffer) {
            Ok(0) => {},
            Ok(nread) => {
                if windows && !binary {
                    // Windows text mode returns '\n' when reading '\r\n'
                    for i in range(0, nread) {
                        if looking_for_newline {
                            if buffer[i] != ('\n' as u8) {
                                vec.push('\r' as u8);
                            }
                            if buffer[i] != ('\r' as u8) {
                                vec.push(buffer[i]);
                                looking_for_newline = false;
                            }
                        } else if buffer[i] != ('\r' as u8) {
                            vec.push(buffer[i]);
                        } else {
                            looking_for_newline = true;
                        }
                    }
                    digest.input(vec.as_slice());
                    vec.clear();
                } else {
                    digest.input(buffer.slice(0, nread));
                }
            },
            Err(e) => match e.kind {
                EndOfFile => {
                    break;
                },
                _ => {
                    return Err(e);
                }
            }
        }
    }
    if windows && looking_for_newline {
        vec.push('\r' as u8);
        digest.input(vec.as_slice());
    }

    Ok(digest.result_str())
}
<|endoftext|>


<commit_before>use libc::{c_char, c_int, wchar_t, FILE};
use core::ptr;
use object::*;
use pystate::PyThreadState;
#[cfg(not(Py_LIMITED_API))]
use pyarena::PyArena;

#[cfg_attr(windows, link(name="pythonXY"))] extern "C" { // TODO: these moved to pylifecycle.h
    pub fn Py_SetProgramName(arg1: *const wchar_t) -> ();
    pub fn Py_GetProgramName() -> *mut wchar_t;
    pub fn Py_SetPythonHome(arg1: *const wchar_t) -> ();
    pub fn Py_GetPythonHome() -> *mut wchar_t;
    pub fn Py_Initialize() -> ();
    pub fn Py_InitializeEx(arg1: c_int) -> ();
    pub fn Py_Finalize() -> ();
    pub fn Py_IsInitialized() -> c_int;
    pub fn Py_NewInterpreter() -> *mut PyThreadState;
    pub fn Py_EndInterpreter(arg1: *mut PyThreadState) -> ();
}

// Note: PyCompilerFlags was moved to compile.h in Python 3.7;
// We still have our version in pythonrun.rs
#[repr(C)]
#[derive(Copy, Clone)]
#[cfg(not(Py_LIMITED_API))]
pub struct PyCompilerFlags {
    cf_flags : c_int
}

#[cfg(not(Py_LIMITED_API))]
pub enum _mod {}

#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    pub fn PyRun_SimpleStringFlags(arg1: *const c_char,
                                   arg2: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_AnyFileFlags(arg1: *mut FILE, arg2: *const c_char,
                              arg3: *mut PyCompilerFlags) -> c_int;
    pub fn PyRun_AnyFileExFlags(fp: *mut FILE,
                                filename: *const c_char,
                                closeit: c_int,
                                flags: *mut PyCompilerFlags) -> c_int;
    pub fn PyRun_SimpleFileExFlags(fp: *mut FILE,
                                   filename: *const c_char,
                                   closeit: c_int,
                                   flags: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_InteractiveOneFlags(fp: *mut FILE,
                                     filename: *const c_char,
                                     flags: *mut PyCompilerFlags)
     -> c_int;
    #[cfg(Py_3_4)]
    pub fn PyRun_InteractiveOneObject(fp: *mut FILE, filename: *mut PyObject,
                                      flags: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_InteractiveLoopFlags(fp: *mut FILE,
                                      filename: *const c_char,
                                      flags: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyParser_ASTFromString(s: *const c_char,
                                  filename: *const c_char,
                                  start: c_int,
                                  flags: *mut PyCompilerFlags,
                                  arena: *mut PyArena) -> *mut _mod;
    #[cfg(Py_3_4)]
    pub fn PyParser_ASTFromStringObject(s: *const c_char,
                                        filename: *mut PyObject,
                                        start: c_int,
                                        flags: *mut PyCompilerFlags,
                                        arena: *mut PyArena)
     -> *mut _mod;
    pub fn PyParser_ASTFromFile(fp: *mut FILE,
                                filename: *const c_char,
                                enc: *const c_char,
                                start: c_int,
                                ps1: *const c_char,
                                ps2: *const c_char,
                                flags: *mut PyCompilerFlags,
                                errcode: *mut c_int,
                                arena: *mut PyArena) -> *mut _mod;
    #[cfg(Py_3_4)]
    pub fn PyParser_ASTFromFileObject(fp: *mut FILE, filename: *mut PyObject,
                                      enc: *const c_char,
                                      start: c_int,
                                      ps1: *const c_char,
                                      ps2: *const c_char,
                                      flags: *mut PyCompilerFlags,
                                      errcode: *mut c_int,
                                      arena: *mut PyArena)
     -> *mut _mod;
}

pub enum symtable {}
pub enum _node {}

#[inline]
pub unsafe fn PyParser_SimpleParseString(s: *const c_char, b: c_int) -> *mut _node {
    PyParser_SimpleParseStringFlags(s, b, 0)
}

#[cfg(not(Py_LIMITED_API))]
#[inline]
pub unsafe fn PyParser_SimpleParseFile(fp: *mut FILE, s: *const c_char, b: c_int) -> *mut _node {
    PyParser_SimpleParseFileFlags(fp, s, b, 0)
}

#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    pub fn PyParser_SimpleParseStringFlags(arg1: *const c_char,
                                           arg2: c_int,
                                           arg3: c_int)
     -> *mut _node;
    pub fn PyParser_SimpleParseStringFlagsFilename(arg1:
                                                       *const c_char,
                                                   arg2:
                                                       *const c_char,
                                                   arg3: c_int,
                                                   arg4: c_int)
     -> *mut _node;
    #[cfg(not(Py_LIMITED_API))]
    pub fn PyParser_SimpleParseFileFlags(arg1: *mut FILE,
                                         arg2: *const c_char,
                                         arg3: c_int,
                                         arg4: c_int)
     -> *mut _node;
    #[cfg(not(Py_LIMITED_API))]
    pub fn PyRun_StringFlags(arg1: *const c_char, arg2: c_int,
                             arg3: *mut PyObject, arg4: *mut PyObject,
                             arg5: *mut PyCompilerFlags) -> *mut PyObject;
    #[cfg(not(Py_LIMITED_API))]
    pub fn PyRun_FileExFlags(fp: *mut FILE, filename: *const c_char,
                             start: c_int, globals: *mut PyObject,
                             locals: *mut PyObject, closeit: c_int,
                             flags: *mut PyCompilerFlags) -> *mut PyObject;
    #[cfg(Py_LIMITED_API)]
    pub fn Py_CompileString(string: *const c_char,
                            p: *const c_char, s: c_int)
     -> *mut PyObject;
}
#[cfg(not(Py_LIMITED_API))]
#[inline]
pub unsafe fn Py_CompileString(string: *const c_char, p: *const c_char, s: c_int) -> *mut PyObject {
    Py_CompileStringExFlags(string, p, s, ptr::null_mut(), -1)
}
#[cfg(not(Py_LIMITED_API))]
#[inline]
pub unsafe fn Py_CompileStringFlags(string: *const c_char, p: *const c_char, s: c_int, f: *mut PyCompilerFlags) -> *mut PyObject {
    Py_CompileStringExFlags(string, p, s, f, -1)
}
#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    #[cfg(not(Py_LIMITED_API))]
    pub fn Py_CompileStringExFlags(str: *const c_char,
                                   filename: *const c_char,
                                   start: c_int,
                                   flags: *mut PyCompilerFlags,
                                   optimize: c_int) -> *mut PyObject;
    #[cfg(not(Py_LIMITED_API))]
    #[cfg(Py_3_4)]
    pub fn Py_CompileStringObject(str: *const c_char,
                                  filename: *mut PyObject,
                                  start: c_int,
                                  flags: *mut PyCompilerFlags,
                                  optimize: c_int) -> *mut PyObject;
    pub fn Py_SymtableString(str: *const c_char,
                             filename: *const c_char,
                             start: c_int) -> *mut symtable;
    #[cfg(not(Py_LIMITED_API))]
    #[cfg(Py_3_4)]
    pub fn Py_SymtableStringObject(str: *const c_char,
                                   filename: *mut PyObject,
                                   start: c_int)
     -> *mut symtable;

    pub fn PyErr_Print() -> ();
    pub fn PyErr_PrintEx(arg1: c_int) -> ();
    pub fn PyErr_Display(arg1: *mut PyObject, arg2: *mut PyObject,
                         arg3: *mut PyObject) -> ();

    // TODO: these moved to pylifecycle.h
    pub fn Py_AtExit(func: Option<extern "C" fn() -> ()>)
     -> c_int;
    pub fn Py_Exit(arg1: c_int) -> ();
    pub fn Py_Main(argc: c_int, argv: *mut *mut wchar_t)
     -> c_int;
    pub fn Py_GetProgramFullPath() -> *mut wchar_t;
    pub fn Py_GetPrefix() -> *mut wchar_t;
    pub fn Py_GetExecPrefix() -> *mut wchar_t;
    pub fn Py_GetPath() -> *mut wchar_t;
    pub fn Py_SetPath(arg1: *const wchar_t) -> ();
    pub fn Py_GetVersion() -> *const c_char;
    pub fn Py_GetPlatform() -> *const c_char;
    pub fn Py_GetCopyright() -> *const c_char;
    pub fn Py_GetCompiler() -> *const c_char;
    pub fn Py_GetBuildInfo() -> *const c_char;
}

<commit_msg>Expose Py_SetStandardStreamEncoding()<commit_after>use libc::{c_char, c_int, wchar_t, FILE};
use core::ptr;
use object::*;
use pystate::PyThreadState;
#[cfg(not(Py_LIMITED_API))]
use pyarena::PyArena;

#[cfg_attr(windows, link(name="pythonXY"))] extern "C" { // TODO: these moved to pylifecycle.h
    #[cfg(Py_3_4)]
    pub fn Py_SetStandardStreamEncoding(encoding: *const c_char, errors: *const c_char) -> c_int;
    pub fn Py_SetProgramName(arg1: *const wchar_t) -> ();
    pub fn Py_GetProgramName() -> *mut wchar_t;
    pub fn Py_SetPythonHome(arg1: *const wchar_t) -> ();
    pub fn Py_GetPythonHome() -> *mut wchar_t;
    pub fn Py_Initialize() -> ();
    pub fn Py_InitializeEx(arg1: c_int) -> ();
    pub fn Py_Finalize() -> ();
    pub fn Py_IsInitialized() -> c_int;
    pub fn Py_NewInterpreter() -> *mut PyThreadState;
    pub fn Py_EndInterpreter(arg1: *mut PyThreadState) -> ();
}

// Note: PyCompilerFlags was moved to compile.h in Python 3.7;
// We still have our version in pythonrun.rs
#[repr(C)]
#[derive(Copy, Clone)]
#[cfg(not(Py_LIMITED_API))]
pub struct PyCompilerFlags {
    cf_flags : c_int
}

#[cfg(not(Py_LIMITED_API))]
pub enum _mod {}

#[cfg(not(Py_LIMITED_API))]
#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    pub fn PyRun_SimpleStringFlags(arg1: *const c_char,
                                   arg2: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_AnyFileFlags(arg1: *mut FILE, arg2: *const c_char,
                              arg3: *mut PyCompilerFlags) -> c_int;
    pub fn PyRun_AnyFileExFlags(fp: *mut FILE,
                                filename: *const c_char,
                                closeit: c_int,
                                flags: *mut PyCompilerFlags) -> c_int;
    pub fn PyRun_SimpleFileExFlags(fp: *mut FILE,
                                   filename: *const c_char,
                                   closeit: c_int,
                                   flags: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_InteractiveOneFlags(fp: *mut FILE,
                                     filename: *const c_char,
                                     flags: *mut PyCompilerFlags)
     -> c_int;
    #[cfg(Py_3_4)]
    pub fn PyRun_InteractiveOneObject(fp: *mut FILE, filename: *mut PyObject,
                                      flags: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_InteractiveLoopFlags(fp: *mut FILE,
                                      filename: *const c_char,
                                      flags: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyParser_ASTFromString(s: *const c_char,
                                  filename: *const c_char,
                                  start: c_int,
                                  flags: *mut PyCompilerFlags,
                                  arena: *mut PyArena) -> *mut _mod;
    #[cfg(Py_3_4)]
    pub fn PyParser_ASTFromStringObject(s: *const c_char,
                                        filename: *mut PyObject,
                                        start: c_int,
                                        flags: *mut PyCompilerFlags,
                                        arena: *mut PyArena)
     -> *mut _mod;
    pub fn PyParser_ASTFromFile(fp: *mut FILE,
                                filename: *const c_char,
                                enc: *const c_char,
                                start: c_int,
                                ps1: *const c_char,
                                ps2: *const c_char,
                                flags: *mut PyCompilerFlags,
                                errcode: *mut c_int,
                                arena: *mut PyArena) -> *mut _mod;
    #[cfg(Py_3_4)]
    pub fn PyParser_ASTFromFileObject(fp: *mut FILE, filename: *mut PyObject,
                                      enc: *const c_char,
                                      start: c_int,
                                      ps1: *const c_char,
                                      ps2: *const c_char,
                                      flags: *mut PyCompilerFlags,
                                      errcode: *mut c_int,
                                      arena: *mut PyArena)
     -> *mut _mod;
}

pub enum symtable {}
pub enum _node {}

#[inline]
pub unsafe fn PyParser_SimpleParseString(s: *const c_char, b: c_int) -> *mut _node {
    PyParser_SimpleParseStringFlags(s, b, 0)
}

#[cfg(not(Py_LIMITED_API))]
#[inline]
pub unsafe fn PyParser_SimpleParseFile(fp: *mut FILE, s: *const c_char, b: c_int) -> *mut _node {
    PyParser_SimpleParseFileFlags(fp, s, b, 0)
}

#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    pub fn PyParser_SimpleParseStringFlags(arg1: *const c_char,
                                           arg2: c_int,
                                           arg3: c_int)
     -> *mut _node;
    pub fn PyParser_SimpleParseStringFlagsFilename(arg1:
                                                       *const c_char,
                                                   arg2:
                                                       *const c_char,
                                                   arg3: c_int,
                                                   arg4: c_int)
     -> *mut _node;
    #[cfg(not(Py_LIMITED_API))]
    pub fn PyParser_SimpleParseFileFlags(arg1: *mut FILE,
                                         arg2: *const c_char,
                                         arg3: c_int,
                                         arg4: c_int)
     -> *mut _node;
    #[cfg(not(Py_LIMITED_API))]
    pub fn PyRun_StringFlags(arg1: *const c_char, arg2: c_int,
                             arg3: *mut PyObject, arg4: *mut PyObject,
                             arg5: *mut PyCompilerFlags) -> *mut PyObject;
    #[cfg(not(Py_LIMITED_API))]
    pub fn PyRun_FileExFlags(fp: *mut FILE, filename: *const c_char,
                             start: c_int, globals: *mut PyObject,
                             locals: *mut PyObject, closeit: c_int,
                             flags: *mut PyCompilerFlags) -> *mut PyObject;
    #[cfg(Py_LIMITED_API)]
    pub fn Py_CompileString(string: *const c_char,
                            p: *const c_char, s: c_int)
     -> *mut PyObject;
}
#[cfg(not(Py_LIMITED_API))]
#[inline]
pub unsafe fn Py_CompileString(string: *const c_char, p: *const c_char, s: c_int) -> *mut PyObject {
    Py_CompileStringExFlags(string, p, s, ptr::null_mut(), -1)
}
#[cfg(not(Py_LIMITED_API))]
#[inline]
pub unsafe fn Py_CompileStringFlags(string: *const c_char, p: *const c_char, s: c_int, f: *mut PyCompilerFlags) -> *mut PyObject {
    Py_CompileStringExFlags(string, p, s, f, -1)
}
#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    #[cfg(not(Py_LIMITED_API))]
    pub fn Py_CompileStringExFlags(str: *const c_char,
                                   filename: *const c_char,
                                   start: c_int,
                                   flags: *mut PyCompilerFlags,
                                   optimize: c_int) -> *mut PyObject;
    #[cfg(not(Py_LIMITED_API))]
    #[cfg(Py_3_4)]
    pub fn Py_CompileStringObject(str: *const c_char,
                                  filename: *mut PyObject,
                                  start: c_int,
                                  flags: *mut PyCompilerFlags,
                                  optimize: c_int) -> *mut PyObject;
    pub fn Py_SymtableString(str: *const c_char,
                             filename: *const c_char,
                             start: c_int) -> *mut symtable;
    #[cfg(not(Py_LIMITED_API))]
    #[cfg(Py_3_4)]
    pub fn Py_SymtableStringObject(str: *const c_char,
                                   filename: *mut PyObject,
                                   start: c_int)
     -> *mut symtable;

    pub fn PyErr_Print() -> ();
    pub fn PyErr_PrintEx(arg1: c_int) -> ();
    pub fn PyErr_Display(arg1: *mut PyObject, arg2: *mut PyObject,
                         arg3: *mut PyObject) -> ();

    // TODO: these moved to pylifecycle.h
    pub fn Py_AtExit(func: Option<extern "C" fn() -> ()>)
     -> c_int;
    pub fn Py_Exit(arg1: c_int) -> ();
    pub fn Py_Main(argc: c_int, argv: *mut *mut wchar_t)
     -> c_int;
    pub fn Py_GetProgramFullPath() -> *mut wchar_t;
    pub fn Py_GetPrefix() -> *mut wchar_t;
    pub fn Py_GetExecPrefix() -> *mut wchar_t;
    pub fn Py_GetPath() -> *mut wchar_t;
    pub fn Py_SetPath(arg1: *const wchar_t) -> ();
    pub fn Py_GetVersion() -> *const c_char;
    pub fn Py_GetPlatform() -> *const c_char;
    pub fn Py_GetCopyright() -> *const c_char;
    pub fn Py_GetCompiler() -> *const c_char;
    pub fn Py_GetBuildInfo() -> *const c_char;
}

<|endoftext|>


<commit_before>//! This crate provides the `#[quickcheck]` attribute. Its use is
//! documented in the `quickcheck` crate.

#![crate_name = "quickcheck_macros"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_root_url = "http://burntsushi.net/rustdoc/quickcheck")]

#![feature(plugin_registrar, managed_boxes)]

extern crate syntax;
extern crate rustc;

use std::gc::{GC, Gc};

use syntax::ast;
use syntax::codemap;
use syntax::parse::token;
use syntax::ext::base::{ExtCtxt, ItemModifier};
use syntax::ext::build::AstBuilder;

use rustc::plugin::Registry;

/// For the `#[quickcheck]` attribute. Do not use.
#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(token::intern("quickcheck"),
                                  ItemModifier(box expand_meta_quickcheck));
}

/// Expands the `#[quickcheck]` attribute.
///
/// Expands:
/// ```
/// #[quickcheck]
/// fn check_something(_: uint) -> bool {
///     true
/// }
/// ```
/// to:
/// ```
/// #[test]
/// fn check_something() {
///     fn check_something(_: uint) -> bool {
///         true
///     }
///     ::quickcheck::quickcheck(check_something)
/// }
/// ```
fn expand_meta_quickcheck(cx: &mut ExtCtxt,
                          span: codemap::Span,
                          _: Gc<ast::MetaItem>,
                          item: Gc<ast::Item>) -> Gc<ast::Item> {
    match item.node {
        ast::ItemFn(..) | ast::ItemStatic(..) => {
            // Copy original function without attributes
            let prop = box(GC) ast::Item {attrs: Vec::new(), ..(*item).clone()};
            // ::quickcheck::quickcheck
            let check_ident = token::str_to_ident("quickcheck");
            let check_path = vec!(check_ident, check_ident);
            // Wrap original function in new outer function, calling ::quickcheck::quickcheck()
            let fn_decl = box(GC) codemap::respan(span, ast::DeclItem(prop));
            let inner_fn = box(GC) codemap::respan(span, ast::StmtDecl(fn_decl, ast::DUMMY_NODE_ID));
            let inner_ident = cx.expr_ident(span, prop.ident);
            let check_call = cx.expr_call_global(span, check_path, vec![inner_ident]);
            let body = cx.block(span, vec![inner_fn], Some(check_call));
            let test = cx.item_fn(span, item.ident, Vec::new(), cx.ty_nil(), body);

            // Copy attributes from original function
            let mut attrs = item.attrs.clone();
            // Add #[test] attribute
            attrs.push(cx.attribute(span, cx.meta_word(span, token::intern_and_get_ident("test"))));
            // Attach the attributes to the outer function
            box(GC) ast::Item {attrs: attrs, ..(*test).clone()}
        },
        _ => {
            cx.span_err(span, "#[quickcheck] only supported on statics and functions");
            item
        }
    }
}
<commit_msg>More changes to bring up to date with master.<commit_after>//! This crate provides the `#[quickcheck]` attribute. Its use is
//! documented in the `quickcheck` crate.

#![crate_name = "quickcheck_macros"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_root_url = "http://burntsushi.net/rustdoc/quickcheck")]

#![feature(plugin_registrar, managed_boxes)]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::codemap;
use syntax::parse::token;
use syntax::ext::base::{ExtCtxt, ItemModifier};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;

use rustc::plugin::Registry;

/// For the `#[quickcheck]` attribute. Do not use.
#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(token::intern("quickcheck"),
                                  ItemModifier(box expand_meta_quickcheck));
}

/// Expands the `#[quickcheck]` attribute.
///
/// Expands:
/// ```
/// #[quickcheck]
/// fn check_something(_: uint) -> bool {
///     true
/// }
/// ```
/// to:
/// ```
/// #[test]
/// fn check_something() {
///     fn check_something(_: uint) -> bool {
///         true
///     }
///     ::quickcheck::quickcheck(check_something)
/// }
/// ```
fn expand_meta_quickcheck(cx: &mut ExtCtxt,
                          span: codemap::Span,
                          _: &ast::MetaItem,
                          item: P<ast::Item>) -> P<ast::Item> {
    match item.node {
        ast::ItemFn(..) | ast::ItemStatic(..) => {
            // Copy original function without attributes
            let prop = P(ast::Item {attrs: Vec::new(), ..(*item).clone()});
            // ::quickcheck::quickcheck
            let check_ident = token::str_to_ident("quickcheck");
            let check_path = vec!(check_ident, check_ident);
            // Wrap original function in new outer function, calling ::quickcheck::quickcheck()
            let fn_decl = P(codemap::respan(span, ast::DeclItem(prop.clone())));
            let inner_fn = P(codemap::respan(span, ast::StmtDecl(fn_decl, ast::DUMMY_NODE_ID)));
            let inner_ident = cx.expr_ident(span, prop.ident);
            let check_call = cx.expr_call_global(span, check_path, vec![inner_ident]);
            let body = cx.block(span, vec![inner_fn], Some(check_call));
            let test = cx.item_fn(span, item.ident, Vec::new(), cx.ty_nil(), body);

            // Copy attributes from original function
            let mut attrs = item.attrs.clone();
            // Add #[test] attribute
            attrs.push(cx.attribute(span, cx.meta_word(span, token::intern_and_get_ident("test"))));
            // Attach the attributes to the outer function
            P(ast::Item {attrs: attrs, ..(*test).clone()})
        },
        _ => {
            cx.span_err(span, "#[quickcheck] only supported on statics and functions");
            item
        }
    }
}
<|endoftext|>


<commit_before>use command::Command;

pub struct Program {
    instructions : Vec<Command>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }
}
<commit_msg>Add program.append(&[Command])<commit_after>use command::Command;

pub struct Program {
    instructions : Vec<Command>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
    }
}
<|endoftext|>


<commit_before>extern crate crypto;
extern crate git2;

use super::build_view;
use super::UnapplyView;
use super::View;
use super::*;
use git2::*;
use std::collections::HashMap;
use std::path::Path;
use std::sync::{Arc, Mutex};

pub type ViewMap = HashMap<Oid, Oid>;

#[derive(Clone)]
pub struct ViewMaps {
    maps: HashMap<String, ViewMap>,
}

impl ViewMaps {
    pub fn set(&mut self, viewstr: &str, from: Oid, to: Oid) {
        let mut m = self
            .maps
            .entry(viewstr.to_string())
            .or_insert_with(ViewMap::new);
        m.insert(from, to);
    }

    pub fn get(&self, viewstr: &str, from: Oid) -> Oid {
        if let Some(m) = self.maps.get(viewstr) {
            return m.get(&from).cloned().unwrap_or_else(Oid::zero);
        }
        return Oid::zero();
    }

    pub fn has(&self, viewstr: &str, from: Oid) -> bool {
        if let Some(m) = self.maps.get(viewstr) {
            return m.contains_key(&from);
        }
        return false;
    }

    pub fn new() -> ViewMaps {
        return ViewMaps {
            maps: HashMap::new(),
        };
    }
}

use self::crypto::digest::Digest;
use self::crypto::sha1::Sha1;

fn all_equal(a: Parents, b: &[&Commit]) -> bool {
    let a: Vec<_> = a.collect();
    if a.len() != b.len() {
        return false;
    }

    for (x, y) in b.iter().zip(a.iter()) {
        if x.id() != y.id() {
            return false;
        }
    }
    return true;
}

// takes everything from base except it's tree and replaces it with the tree
// given
pub fn rewrite(repo: &Repository, base: &Commit, parents: &[&Commit], tree: &Tree) -> Oid {
    if base.tree().unwrap().id() == tree.id() && all_equal(base.parents(), parents) {
        // Looks like an optimization, but in fact serves to not change the commit in case
        // it was signed.
        return base.id();
    }

    let result = repo
        .commit(
            None,
            &base.author(),
            &base.committer(),
            &base.message().unwrap_or("no message"),
            tree,
            parents,
        )
        .expect("rewrite: can't commit {:?}");

    result
}

pub fn unapply_view(
    repo: &Repository,
    backward_maps: Arc<Mutex<ViewMaps>>,
    viewobj: &View,
    old: Oid,
    new: Oid,
) -> UnapplyView {
    trace_scoped!(
        "unapply_view",
        "repo": repo.path(),
        "old": format!("{:?}", old),
        "new": format!("{:?}", new));
    debug!("unapply_view");

    if old == new {
        return UnapplyView::NoChanges;
    }

    let current = {
        let mut backward_maps = backward_maps.lock().unwrap();

        let current = backward_maps.get(&viewobj.viewstr(), old);
        if current == Oid::zero() {
            debug!("not in backward_maps({},{})", viewobj.viewstr(), old);
            return UnapplyView::RejectNoFF;
        }
        current
    };

    match repo.graph_descendant_of(new, old) {
        Err(_) | Ok(false) => {
            debug!("graph_descendant_of({},{})", new, old);
            return UnapplyView::RejectNoFF;
        }
        Ok(true) => (),
    }

    debug!("==== walking commits from {} to {}", old, new);

    let walk = {
        let mut walk = repo.revwalk().expect("walk: can't create revwalk");
        walk.set_sorting(Sort::REVERSE | Sort::TOPOLOGICAL);
        walk.push(new).expect("walk.push");
        walk.hide(old).expect("walk: can't hide");
        walk
    };

    let mut current = current;
    for rev in walk {
        let rev = rev.expect("walk: invalid rev");

        debug!("==== walking commit {}", rev);

        let module_commit = repo
            .find_commit(rev)
            .expect("walk: object is not actually a commit");

        if module_commit.parents().count() > 1 {
            // TODO: invectigate the possibility of allowing merge commits
            return UnapplyView::RejectMerge;
        }

        debug!("==== Rewriting commit {}", rev);

        let tree = module_commit.tree().expect("walk: commit has no tree");
        let parent = repo
            .find_commit(current)
            .expect("walk: current object is no commit");

        let new_tree = viewobj.unapply(
            &repo,
            &tree,
            &parent.tree().expect("walk: parent has no tree"),
        );

        let new_tree = repo.find_tree(new_tree).expect("can't find rewritten tree");
        let check = viewobj.apply_to_tree(&repo, &new_tree);

        current = rewrite(&repo, &module_commit, &[&parent], &new_tree);
    }

    return UnapplyView::Done(current);
}

pub fn new(path: &Path) -> Repository {
    Repository::init_bare(&path).expect("could not init scratch")
}

fn transform_commit(
    repo: &Repository,
    viewobj: &View,
    from_refsname: &str,
    to_refname: &str,
    forward_maps: &mut ViewMaps,
    backward_maps: &mut ViewMaps,
) {
    if let Ok(reference) = repo.find_reference(&from_refsname) {
        let r = reference.target().expect("no ref");

        let view_commit = apply_view_cached(&repo, &*viewobj, r, forward_maps, backward_maps);
        if view_commit != git2::Oid::zero() {
            repo.reference(&to_refname, view_commit, true, "apply_view")
                .expect("can't create reference");
        }
    };
}

pub fn apply_view_to_branch(
    repo: &Repository,
    branchname: &str,
    viewobj: &dyn View,
    forward_maps: &mut ViewMaps,
    backward_maps: &mut ViewMaps,
    ns: &str,
) {
    trace_scoped!(
        "apply_view_to_branch",
        "repo": repo.path(),
        "branchname": branchname,
        "viewstr": viewobj.viewstr());

    let to_branch = format!("refs/namespaces/{}/refs/heads/{}", &ns, &branchname);
    let to_refs_for = format!("refs/namespaces/{}/refs/for/{}", &ns, &branchname);
    let to_refs_drafts = format!("refs/namespaces/{}/refs/drafts/{}", &ns, &branchname);
    let to_head = format!("refs/namespaces/{}/HEAD", &ns);
    let from_refsname = format!("refs/heads/{}", branchname);

    debug!("apply_view_to_branch {}", branchname);
    transform_commit(
        &repo,
        &*viewobj,
        &from_refsname,
        &to_branch,
        forward_maps,
        backward_maps,
    );
    transform_commit(
        &repo,
        &*viewobj,
        &from_refsname,
        &to_refs_for,
        forward_maps,
        backward_maps,
    );
    transform_commit(
        &repo,
        &*viewobj,
        &from_refsname,
        &to_refs_drafts,
        forward_maps,
        backward_maps,
    );

    if branchname == "master" {
        transform_commit(
            &repo,
            &*viewobj,
            "refs/heads/master",
            &to_head,
            forward_maps,
            backward_maps,
        );
    }
}

pub fn apply_view_cached(
    repo: &Repository,
    view: &dyn View,
    newrev: Oid,
    forward_maps: &mut ViewMaps,
    backward_maps: &mut ViewMaps,
) -> Oid {
    if forward_maps.has(&view.viewstr(), newrev) {
        return forward_maps.get(&view.viewstr(), newrev);
    }

    let tname = format!("apply_view_cached {:?}", newrev);
    trace_begin!(&tname, "viewstr": view.viewstr());

    let walk = {
        let mut walk = repo.revwalk().expect("walk: can't create revwalk");
        walk.set_sorting(Sort::REVERSE | Sort::TOPOLOGICAL);
        walk.push(newrev).expect("walk.push");
        walk
    };

    let empty = empty_tree(repo).id();

    let mut in_commit_count = 0;
    let mut out_commit_count = 0;
    let mut empty_tree_count = 0;
    'walk: for commit in walk {
        in_commit_count += 1;
        let commit = repo.find_commit(commit.unwrap()).unwrap();

        if forward_maps.has(&view.viewstr(), commit.id()) {
            continue 'walk;
        }

        let (new_tree, transformed_parents_ids) =
            view.apply_to_commit(&repo, &commit, forward_maps, backward_maps);

        if new_tree == empty {
            empty_tree_count += 1;
            continue 'walk;
        }

        let mut transformed_parents = vec![];
        for parent_id in transformed_parents_ids {
            if let Ok(parent) = repo.find_commit(parent_id) {
                transformed_parents.push(parent);
            }
        }

        let transformed_parent_refs: Vec<&_> = transformed_parents.iter().collect();
        let mut filtered_transformed_parent_refs: Vec<&_> = vec![];

        for transformed_parent in transformed_parent_refs {
            if new_tree != transformed_parent.tree().unwrap().id() {
                filtered_transformed_parent_refs.push(transformed_parent);
                continue;
            }
            if commit.tree().expect("missing tree").id()
                == commit.parents().next().unwrap().tree().unwrap().id()
            {
                filtered_transformed_parent_refs.push(transformed_parent);
                continue;
            }
        }

        if filtered_transformed_parent_refs.len() == 0 && transformed_parents.len() != 0 {
            forward_maps.set(&view.viewstr(), commit.id(), transformed_parents[0].id());
            continue 'walk;
        }

        let new_tree = repo
            .find_tree(new_tree)
            .expect("apply_view_cached: can't find tree");
        let transformed = rewrite(&repo, &commit, &filtered_transformed_parent_refs, &new_tree);
        forward_maps.set(&view.viewstr(), commit.id(), transformed);
        backward_maps.set(&view.viewstr(), transformed, commit.id());
        out_commit_count += 1;
    }

    trace_end!(
        &tname,
        "in_commit_count": in_commit_count,
        "out_commit_count": out_commit_count,
        "empty_tree_count": empty_tree_count
    );

    if !forward_maps.has(&view.viewstr(), newrev) {
        forward_maps.set(&view.viewstr(), newrev, Oid::zero());
    }
    return forward_maps.get(&view.viewstr(), newrev);
}
<commit_msg>ViewMaps should not be Clone<commit_after>extern crate crypto;
extern crate git2;

use super::build_view;
use super::UnapplyView;
use super::View;
use super::*;
use git2::*;
use std::collections::HashMap;
use std::path::Path;
use std::sync::{Arc, Mutex};

pub type ViewMap = HashMap<Oid, Oid>;

pub struct ViewMaps {
    maps: HashMap<String, ViewMap>,
}

impl ViewMaps {
    pub fn set(&mut self, viewstr: &str, from: Oid, to: Oid) {
        let mut m = self
            .maps
            .entry(viewstr.to_string())
            .or_insert_with(ViewMap::new);
        m.insert(from, to);
    }

    pub fn get(&self, viewstr: &str, from: Oid) -> Oid {
        if let Some(m) = self.maps.get(viewstr) {
            return m.get(&from).cloned().unwrap_or_else(Oid::zero);
        }
        return Oid::zero();
    }

    pub fn has(&self, viewstr: &str, from: Oid) -> bool {
        if let Some(m) = self.maps.get(viewstr) {
            return m.contains_key(&from);
        }
        return false;
    }

    pub fn new() -> ViewMaps {
        return ViewMaps {
            maps: HashMap::new(),
        };
    }
}

use self::crypto::digest::Digest;
use self::crypto::sha1::Sha1;

fn all_equal(a: Parents, b: &[&Commit]) -> bool {
    let a: Vec<_> = a.collect();
    if a.len() != b.len() {
        return false;
    }

    for (x, y) in b.iter().zip(a.iter()) {
        if x.id() != y.id() {
            return false;
        }
    }
    return true;
}

// takes everything from base except it's tree and replaces it with the tree
// given
pub fn rewrite(repo: &Repository, base: &Commit, parents: &[&Commit], tree: &Tree) -> Oid {
    if base.tree().unwrap().id() == tree.id() && all_equal(base.parents(), parents) {
        // Looks like an optimization, but in fact serves to not change the commit in case
        // it was signed.
        return base.id();
    }

    let result = repo
        .commit(
            None,
            &base.author(),
            &base.committer(),
            &base.message().unwrap_or("no message"),
            tree,
            parents,
        )
        .expect("rewrite: can't commit {:?}");

    result
}

pub fn unapply_view(
    repo: &Repository,
    backward_maps: Arc<Mutex<ViewMaps>>,
    viewobj: &View,
    old: Oid,
    new: Oid,
) -> UnapplyView {
    trace_scoped!(
        "unapply_view",
        "repo": repo.path(),
        "old": format!("{:?}", old),
        "new": format!("{:?}", new));
    debug!("unapply_view");

    if old == new {
        return UnapplyView::NoChanges;
    }

    let current = {
        let mut backward_maps = backward_maps.lock().unwrap();

        let current = backward_maps.get(&viewobj.viewstr(), old);
        if current == Oid::zero() {
            debug!("not in backward_maps({},{})", viewobj.viewstr(), old);
            return UnapplyView::RejectNoFF;
        }
        current
    };

    match repo.graph_descendant_of(new, old) {
        Err(_) | Ok(false) => {
            debug!("graph_descendant_of({},{})", new, old);
            return UnapplyView::RejectNoFF;
        }
        Ok(true) => (),
    }

    debug!("==== walking commits from {} to {}", old, new);

    let walk = {
        let mut walk = repo.revwalk().expect("walk: can't create revwalk");
        walk.set_sorting(Sort::REVERSE | Sort::TOPOLOGICAL);
        walk.push(new).expect("walk.push");
        walk.hide(old).expect("walk: can't hide");
        walk
    };

    let mut current = current;
    for rev in walk {
        let rev = rev.expect("walk: invalid rev");

        debug!("==== walking commit {}", rev);

        let module_commit = repo
            .find_commit(rev)
            .expect("walk: object is not actually a commit");

        if module_commit.parents().count() > 1 {
            // TODO: invectigate the possibility of allowing merge commits
            return UnapplyView::RejectMerge;
        }

        debug!("==== Rewriting commit {}", rev);

        let tree = module_commit.tree().expect("walk: commit has no tree");
        let parent = repo
            .find_commit(current)
            .expect("walk: current object is no commit");

        let new_tree = viewobj.unapply(
            &repo,
            &tree,
            &parent.tree().expect("walk: parent has no tree"),
        );

        let new_tree = repo.find_tree(new_tree).expect("can't find rewritten tree");
        let check = viewobj.apply_to_tree(&repo, &new_tree);

        current = rewrite(&repo, &module_commit, &[&parent], &new_tree);
    }

    return UnapplyView::Done(current);
}

pub fn new(path: &Path) -> Repository {
    Repository::init_bare(&path).expect("could not init scratch")
}

fn transform_commit(
    repo: &Repository,
    viewobj: &View,
    from_refsname: &str,
    to_refname: &str,
    forward_maps: &mut ViewMaps,
    backward_maps: &mut ViewMaps,
) {
    if let Ok(reference) = repo.find_reference(&from_refsname) {
        let r = reference.target().expect("no ref");

        let view_commit = apply_view_cached(&repo, &*viewobj, r, forward_maps, backward_maps);
        if view_commit != git2::Oid::zero() {
            repo.reference(&to_refname, view_commit, true, "apply_view")
                .expect("can't create reference");
        }
    };
}

pub fn apply_view_to_branch(
    repo: &Repository,
    branchname: &str,
    viewobj: &dyn View,
    forward_maps: &mut ViewMaps,
    backward_maps: &mut ViewMaps,
    ns: &str,
) {
    trace_scoped!(
        "apply_view_to_branch",
        "repo": repo.path(),
        "branchname": branchname,
        "viewstr": viewobj.viewstr());

    let to_branch = format!("refs/namespaces/{}/refs/heads/{}", &ns, &branchname);
    let to_refs_for = format!("refs/namespaces/{}/refs/for/{}", &ns, &branchname);
    let to_refs_drafts = format!("refs/namespaces/{}/refs/drafts/{}", &ns, &branchname);
    let to_head = format!("refs/namespaces/{}/HEAD", &ns);
    let from_refsname = format!("refs/heads/{}", branchname);

    debug!("apply_view_to_branch {}", branchname);
    transform_commit(
        &repo,
        &*viewobj,
        &from_refsname,
        &to_branch,
        forward_maps,
        backward_maps,
    );
    transform_commit(
        &repo,
        &*viewobj,
        &from_refsname,
        &to_refs_for,
        forward_maps,
        backward_maps,
    );
    transform_commit(
        &repo,
        &*viewobj,
        &from_refsname,
        &to_refs_drafts,
        forward_maps,
        backward_maps,
    );

    if branchname == "master" {
        transform_commit(
            &repo,
            &*viewobj,
            "refs/heads/master",
            &to_head,
            forward_maps,
            backward_maps,
        );
    }
}

pub fn apply_view_cached(
    repo: &Repository,
    view: &dyn View,
    newrev: Oid,
    forward_maps: &mut ViewMaps,
    backward_maps: &mut ViewMaps,
) -> Oid {
    if forward_maps.has(&view.viewstr(), newrev) {
        return forward_maps.get(&view.viewstr(), newrev);
    }

    let tname = format!("apply_view_cached {:?}", newrev);
    trace_begin!(&tname, "viewstr": view.viewstr());

    let walk = {
        let mut walk = repo.revwalk().expect("walk: can't create revwalk");
        walk.set_sorting(Sort::REVERSE | Sort::TOPOLOGICAL);
        walk.push(newrev).expect("walk.push");
        walk
    };

    let empty = empty_tree(repo).id();

    let mut in_commit_count = 0;
    let mut out_commit_count = 0;
    let mut empty_tree_count = 0;
    'walk: for commit in walk {
        in_commit_count += 1;
        let commit = repo.find_commit(commit.unwrap()).unwrap();

        if forward_maps.has(&view.viewstr(), commit.id()) {
            continue 'walk;
        }

        let (new_tree, transformed_parents_ids) =
            view.apply_to_commit(&repo, &commit, forward_maps, backward_maps);

        if new_tree == empty {
            empty_tree_count += 1;
            continue 'walk;
        }

        let mut transformed_parents = vec![];
        for parent_id in transformed_parents_ids {
            if let Ok(parent) = repo.find_commit(parent_id) {
                transformed_parents.push(parent);
            }
        }

        let transformed_parent_refs: Vec<&_> = transformed_parents.iter().collect();
        let mut filtered_transformed_parent_refs: Vec<&_> = vec![];

        for transformed_parent in transformed_parent_refs {
            if new_tree != transformed_parent.tree().unwrap().id() {
                filtered_transformed_parent_refs.push(transformed_parent);
                continue;
            }
            if commit.tree().expect("missing tree").id()
                == commit.parents().next().unwrap().tree().unwrap().id()
            {
                filtered_transformed_parent_refs.push(transformed_parent);
                continue;
            }
        }

        if filtered_transformed_parent_refs.len() == 0 && transformed_parents.len() != 0 {
            forward_maps.set(&view.viewstr(), commit.id(), transformed_parents[0].id());
            continue 'walk;
        }

        let new_tree = repo
            .find_tree(new_tree)
            .expect("apply_view_cached: can't find tree");
        let transformed = rewrite(&repo, &commit, &filtered_transformed_parent_refs, &new_tree);
        forward_maps.set(&view.viewstr(), commit.id(), transformed);
        backward_maps.set(&view.viewstr(), transformed, commit.id());
        out_commit_count += 1;
    }

    trace_end!(
        &tname,
        "in_commit_count": in_commit_count,
        "out_commit_count": out_commit_count,
        "empty_tree_count": empty_tree_count
    );

    if !forward_maps.has(&view.viewstr(), newrev) {
        forward_maps.set(&view.viewstr(), newrev, Oid::zero());
    }
    return forward_maps.get(&view.viewstr(), newrev);
}
<|endoftext|>


<commit_before>//! Service
//!  - Initialize persistent cache
//!  - Initialize cleaning daemon
//!  - Initialize loggers
//!  - Mount url endpoints to `handlers` functions
//!  - Mount static file handler
//!
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use chrono::{DateTime, UTC};
use time;
use iron::prelude::*;
use iron::status;
use iron::middleware::{BeforeMiddleware, AfterMiddleware};
use iron::headers::{CacheControl, CacheDirective, Expires, HttpDate};
use router::{Router, NoRoute};
use mount::Mount;
use staticfile::Static;
use logger;
use env_logger;

use routes;
use handlers;

pub static DT_FORMAT: &'static str = "%Y-%m-%d_%H:%M:%S";

pub struct Record {
    pub last_refresh: DateTime<UTC>,
    pub path_buf: PathBuf,
}
impl Record {
    pub fn from_path_buf(pb: &PathBuf) -> Self {
        Self {
            last_refresh: UTC::now(),
            path_buf: pb.clone(),
        }
    }
}

pub type Cache = Arc<Mutex<HashMap<String, Option<Record>>>>;

/// Custom logger to print out access info
pub struct InfoLog;
impl BeforeMiddleware for InfoLog {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        let now = UTC::now().format(DT_FORMAT).to_string();
        println!("[{:?}][{}]: {}", req.method, now, req.url);
        Ok(())
    }
    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<()> {
        let now = UTC::now().format(DT_FORMAT).to_string();
        println!("[{:?}][{}]: {} -> {}", req.method, now, req.url, err);
        Err(err)
    }
}

/// Custom `CacheControl` header settings
/// Applies a `Cache-Control: max-age=3600` if no `CacheControl` header is already set.
/// Applies a `Expires: now + 1hr` if no `Expires` header is already set.
pub struct DefaultCacheSettings;
impl AfterMiddleware for DefaultCacheSettings {
    fn after(&self, _req: &mut Request, mut resp: Response) -> IronResult<Response> {
        if resp.headers.get::<CacheControl>().is_none() {
            resp.headers.set(
                CacheControl(vec![
                    CacheDirective::MaxAge(3600u32), // 1hr
                    CacheDirective::Public,
                ]));
        }
        if resp.headers.get::<Expires>().is_none() {
            resp.headers.set(
                Expires(HttpDate(time::now() + time::Duration::hours(1)))
                );
        }
        Ok(resp)
    }
}

static ERROR_404: &'static str = r##"

Nothing to see here...

"##;

struct Error404;
impl AfterMiddleware for Error404 {
    fn catch(&self, _req: &mut Request, e: IronError) -> IronResult<Response> {
        if let Some(_) = e.error.downcast::<NoRoute>() {
            return Ok(Response::with((status::NotFound, mime!(Text/Html), ERROR_404)))
        }
        Err(e)
    }
}

/// Initialize server
pub fn start(host: &str, log_access: bool) {
    // get default host
    let host = if host.is_empty() { "localhost:3000" } else { host };

    // setup our cache
    let cache = Arc::new(Mutex::new(HashMap::new()));

    // initialize cleaning thread
    handlers::init_cleaner(cache.clone());

    // initialize handlers with access to our cache
    let handlers_ = handlers::initialize(cache.clone());

    // mount our url endpoints
    let mut router = Router::new();
    routes::mount(&mut router, &handlers_);

    // Initialize our Chain with our router,
    let mut chain = Chain::new(router);

    // Initialize and link our error loggers and CacheControl Middleware
    env_logger::init().unwrap();
    let (log_before, log_after) = logger::Logger::new(None);
    chain.link_before(log_before);
    chain.link_after(DefaultCacheSettings);
    chain.link_after(log_after);
    chain.link_after(Error404);

    // Link our access logger if we're logging
    if log_access {
        chain.link_before(InfoLog);
    }

    // mount our chain of services and a static file handler
    let mut mount = Mount::new();
    mount.mount("/", chain)
         .mount("/favicon.ico", Static::new(Path::new("static/favicon.ico")))
         .mount("/static/", Static::new(Path::new("static")));

    println!(" ** Serving at {}", host);
    Iron::new(mount).http(host).unwrap();
}
<commit_msg>misc<commit_after>//! Service
//!  - Initialize persistent cache
//!  - Initialize cleaning daemon
//!  - Initialize loggers
//!  - Mount url endpoints to `handlers` functions
//!  - Mount static file handler
//!
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use chrono::{DateTime, UTC};
use time;
use iron::prelude::*;
use iron::status;
use iron::middleware::{BeforeMiddleware, AfterMiddleware};
use iron::headers::{CacheControl, CacheDirective, Expires, HttpDate};
use router::{Router, NoRoute};
use mount::Mount;
use staticfile::Static;
use logger;
use env_logger;

use routes;
use handlers;

pub static DT_FORMAT: &'static str = "%Y-%m-%d_%H:%M:%S";

pub struct Record {
    pub last_refresh: DateTime<UTC>,
    pub path_buf: PathBuf,
}
impl Record {
    pub fn from_path_buf(pb: &PathBuf) -> Self {
        Self {
            last_refresh: UTC::now(),
            path_buf: pb.clone(),
        }
    }
}

pub type Cache = Arc<Mutex<HashMap<String, Option<Record>>>>;

/// Custom logger to print out access info
struct InfoLog;
impl BeforeMiddleware for InfoLog {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        let now = UTC::now().format(DT_FORMAT).to_string();
        println!("[{:?}][{}]: {}", req.method, now, req.url);
        Ok(())
    }
    fn catch(&self, req: &mut Request, err: IronError) -> IronResult<()> {
        let now = UTC::now().format(DT_FORMAT).to_string();
        println!("[{:?}][{}]: {} -> {}", req.method, now, req.url, err);
        Err(err)
    }
}

/// Custom `CacheControl` header settings
/// Applies a `Cache-Control: max-age=3600` if no `CacheControl` header is already set.
/// Applies a `Expires: now + 1hr` if no `Expires` header is already set.
struct DefaultCacheSettings;
impl AfterMiddleware for DefaultCacheSettings {
    fn after(&self, _req: &mut Request, mut resp: Response) -> IronResult<Response> {
        if resp.headers.get::<CacheControl>().is_none() {
            resp.headers.set(
                CacheControl(vec![
                    CacheDirective::MaxAge(3600u32), // 1hr
                    CacheDirective::Public,
                ]));
        }
        if resp.headers.get::<Expires>().is_none() {
            resp.headers.set(
                Expires(HttpDate(time::now() + time::Duration::hours(1)))
                );
        }
        Ok(resp)
    }
}

static ERROR_404: &'static str = r##"

        Nothing to see here...

"##;

/// Custom 404 Error handler/content
struct Error404;
impl AfterMiddleware for Error404 {
    fn catch(&self, _req: &mut Request, e: IronError) -> IronResult<Response> {
        if let Some(_) = e.error.downcast::<NoRoute>() {
            return Ok(Response::with((status::NotFound, mime!(Text/Html), ERROR_404)))
        }
        Err(e)
    }
}

/// Initialize server
pub fn start(host: &str, log_access: bool) {
    // get default host
    let host = if host.is_empty() { "localhost:3000" } else { host };

    // setup our cache
    let cache = Arc::new(Mutex::new(HashMap::new()));

    // initialize cleaning thread
    handlers::init_cleaner(cache.clone());

    // initialize handlers with access to our cache
    let handlers_ = handlers::initialize(cache.clone());

    // mount our url endpoints
    let mut router = Router::new();
    routes::mount(&mut router, &handlers_);

    // Initialize our Chain with our router,
    let mut chain = Chain::new(router);

    // Initialize and link our error loggers and CacheControl Middleware
    env_logger::init().unwrap();
    let (log_before, log_after) = logger::Logger::new(None);
    chain.link_before(log_before);
    chain.link_after(DefaultCacheSettings);
    chain.link_after(log_after);
    chain.link_after(Error404);

    // Link our access logger if we're logging
    if log_access {
        chain.link_before(InfoLog);
    }

    // mount our chain of services and a static file handler
    let mut mount = Mount::new();
    mount.mount("/", chain)
         .mount("/favicon.ico", Static::new(Path::new("static/favicon.ico")))
         .mount("/static/", Static::new(Path::new("static")));

    println!(" ** Serving at {}", host);
    Iron::new(mount).http(host).unwrap();
}
<|endoftext|>


<commit_before>//! This LintPass catches both string addition and string addition + assignment
//!
//! Note that since we have two lints where one subsumes the other, we try to
//! disable the subsumed lint unless it has a higher level

use rustc::lint::*;
use rustc_front::hir::*;
use syntax::codemap::Spanned;

use utils::{match_type, span_lint, walk_ptrs_ty, get_parent_expr};
use utils::SpanlessEq;
use utils::STRING_PATH;

/// **What it does:** This lint matches code of the form `x = x + y` (without `let`!).
///
/// **Why is this bad?** Because this expression needs another copy as opposed to `x.push_str(y)` (in practice LLVM will usually elide it, though). Despite [llogiq](https://github.com/llogiq)'s reservations, this lint also is `allow` by default, as some people opine that it's more readable.
///
/// **Known problems:** None. Well apart from the lint being `allow` by default. :smile:
///
/// **Example:**
///
/// ```
/// let mut x = "Hello".to_owned();
/// x = x + ", World";
/// ```
declare_lint! {
    pub STRING_ADD_ASSIGN,
    Allow,
    "using `x = x + ..` where x is a `String`; suggests using `push_str()` instead"
}

/// **What it does:** The `string_add` lint matches all instances of `x + _` where `x` is of type `String`, but only if [`string_add_assign`](#string_add_assign) does *not* match.
///
/// **Why is this bad?** It's not bad in and of itself. However, this particular `Add` implementation is asymmetric (the other operand need not be `String`, but `x` does), while addition as mathematically defined is symmetric, also the `String::push_str(_)` function is a perfectly good replacement. Therefore some dislike it and wish not to have it in their code.
///
/// That said, other people think that String addition, having a long tradition in other languages is actually fine, which is why we decided to make this particular lint `allow` by default.
///
/// **Known problems:** None
///
/// **Example:**
///
/// ```
/// let x = "Hello".to_owned();
/// x + ", World"
/// ```
declare_lint! {
    pub STRING_ADD,
    Allow,
    "using `x + ..` where x is a `String`; suggests using `push_str()` instead"
}

/// **What it does:** This lint matches the `as_bytes` method called on string
/// literals that contain only ascii characters.
///
/// **Why is this bad?** Byte string literals (e.g. `b"foo"`) can be used instead. They are shorter but less discoverable than `as_bytes()`.
///
/// **Example:**
///
/// ```
/// let bs = "a byte string".as_bytes();
/// ```
declare_lint! {
    pub STRING_LIT_AS_BYTES,
    Warn,
    "calling `as_bytes` on a string literal; suggests using a byte string literal instead"
}

#[derive(Copy, Clone)]
pub struct StringAdd;

impl LintPass for StringAdd {
    fn get_lints(&self) -> LintArray {
        lint_array!(STRING_ADD, STRING_ADD_ASSIGN)
    }
}

impl LateLintPass for StringAdd {
    fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
        if let ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) = e.node {
            if is_string(cx, left) {
                if let Allow = cx.current_level(STRING_ADD_ASSIGN) {
                    // the string_add_assign is allow, so no duplicates
                } else {
                    let parent = get_parent_expr(cx, e);
                    if let Some(ref p) = parent {
                        if let ExprAssign(ref target, _) = p.node {
                            // avoid duplicate matches
                            if SpanlessEq::new(cx).eq_expr(target, left) {
                                return;
                            }
                        }
                    }
                }
                span_lint(cx,
                          STRING_ADD,
                          e.span,
                          "you added something to a string. Consider using `String::push_str()` instead");
            }
        } else if let ExprAssign(ref target, ref src) = e.node {
            if is_string(cx, target) && is_add(cx, src, target) {
                span_lint(cx,
                          STRING_ADD_ASSIGN,
                          e.span,
                          "you assigned the result of adding something to this string. Consider using \
                           `String::push_str()` instead");
            }
        }
    }
}

fn is_string(cx: &LateContext, e: &Expr) -> bool {
    match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(e)), &STRING_PATH)
}

fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool {
    match src.node {
        ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left),
        ExprBlock(ref block) => {
            block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
        }
        _ => false,
    }
}

#[derive(Copy, Clone)]
pub struct StringLitAsBytes;

impl LintPass for StringLitAsBytes {
    fn get_lints(&self) -> LintArray {
        lint_array!(STRING_LIT_AS_BYTES)
    }
}

impl LateLintPass for StringLitAsBytes {
    fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
        use std::ascii::AsciiExt;
        use syntax::ast::LitKind;
        use utils::{snippet, in_macro};

        if let ExprMethodCall(ref name, _, ref args) = e.node {
            if name.node.as_str() == "as_bytes" {
                if let ExprLit(ref lit) = args[0].node {
                    if let LitKind::Str(ref lit_content, _) = lit.node {
                        if lit_content.chars().all(|c| c.is_ascii()) && !in_macro(cx, e.span) {
                            let msg = format!("calling `as_bytes()` on a string literal. \
                                               Consider using a byte string literal instead: \
                                               `b{}`",
                                               snippet(cx, args[0].span, r#""foo""#));
                            span_lint(cx, STRING_LIT_AS_BYTES, e.span, &msg);
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>improve str_add_assign lint description<commit_after>//! This LintPass catches both string addition and string addition + assignment
//!
//! Note that since we have two lints where one subsumes the other, we try to
//! disable the subsumed lint unless it has a higher level

use rustc::lint::*;
use rustc_front::hir::*;
use syntax::codemap::Spanned;

use utils::{match_type, span_lint, walk_ptrs_ty, get_parent_expr};
use utils::SpanlessEq;
use utils::STRING_PATH;

/// **What it does:** This lint matches code of the form `x = x + y` (without `let`!).
///
/// **Why is this bad?** It's not really bad, but some people think that the `.push_str(_)` method is more readable.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```
/// let mut x = "Hello".to_owned();
/// x = x + ", World";
/// ```
declare_lint! {
    pub STRING_ADD_ASSIGN,
    Allow,
    "using `x = x + ..` where x is a `String`; suggests using `push_str()` instead"
}

/// **What it does:** The `string_add` lint matches all instances of `x + _` where `x` is of type `String`, but only if [`string_add_assign`](#string_add_assign) does *not* match.
///
/// **Why is this bad?** It's not bad in and of itself. However, this particular `Add` implementation is asymmetric (the other operand need not be `String`, but `x` does), while addition as mathematically defined is symmetric, also the `String::push_str(_)` function is a perfectly good replacement. Therefore some dislike it and wish not to have it in their code.
///
/// That said, other people think that String addition, having a long tradition in other languages is actually fine, which is why we decided to make this particular lint `allow` by default.
///
/// **Known problems:** None
///
/// **Example:**
///
/// ```
/// let x = "Hello".to_owned();
/// x + ", World"
/// ```
declare_lint! {
    pub STRING_ADD,
    Allow,
    "using `x + ..` where x is a `String`; suggests using `push_str()` instead"
}

/// **What it does:** This lint matches the `as_bytes` method called on string
/// literals that contain only ascii characters.
///
/// **Why is this bad?** Byte string literals (e.g. `b"foo"`) can be used instead. They are shorter but less discoverable than `as_bytes()`.
///
/// **Example:**
///
/// ```
/// let bs = "a byte string".as_bytes();
/// ```
declare_lint! {
    pub STRING_LIT_AS_BYTES,
    Warn,
    "calling `as_bytes` on a string literal; suggests using a byte string literal instead"
}

#[derive(Copy, Clone)]
pub struct StringAdd;

impl LintPass for StringAdd {
    fn get_lints(&self) -> LintArray {
        lint_array!(STRING_ADD, STRING_ADD_ASSIGN)
    }
}

impl LateLintPass for StringAdd {
    fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
        if let ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) = e.node {
            if is_string(cx, left) {
                if let Allow = cx.current_level(STRING_ADD_ASSIGN) {
                    // the string_add_assign is allow, so no duplicates
                } else {
                    let parent = get_parent_expr(cx, e);
                    if let Some(ref p) = parent {
                        if let ExprAssign(ref target, _) = p.node {
                            // avoid duplicate matches
                            if SpanlessEq::new(cx).eq_expr(target, left) {
                                return;
                            }
                        }
                    }
                }
                span_lint(cx,
                          STRING_ADD,
                          e.span,
                          "you added something to a string. Consider using `String::push_str()` instead");
            }
        } else if let ExprAssign(ref target, ref src) = e.node {
            if is_string(cx, target) && is_add(cx, src, target) {
                span_lint(cx,
                          STRING_ADD_ASSIGN,
                          e.span,
                          "you assigned the result of adding something to this string. Consider using \
                           `String::push_str()` instead");
            }
        }
    }
}

fn is_string(cx: &LateContext, e: &Expr) -> bool {
    match_type(cx, walk_ptrs_ty(cx.tcx.expr_ty(e)), &STRING_PATH)
}

fn is_add(cx: &LateContext, src: &Expr, target: &Expr) -> bool {
    match src.node {
        ExprBinary(Spanned{ node: BiAdd, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left),
        ExprBlock(ref block) => {
            block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
        }
        _ => false,
    }
}

#[derive(Copy, Clone)]
pub struct StringLitAsBytes;

impl LintPass for StringLitAsBytes {
    fn get_lints(&self) -> LintArray {
        lint_array!(STRING_LIT_AS_BYTES)
    }
}

impl LateLintPass for StringLitAsBytes {
    fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
        use std::ascii::AsciiExt;
        use syntax::ast::LitKind;
        use utils::{snippet, in_macro};

        if let ExprMethodCall(ref name, _, ref args) = e.node {
            if name.node.as_str() == "as_bytes" {
                if let ExprLit(ref lit) = args[0].node {
                    if let LitKind::Str(ref lit_content, _) = lit.node {
                        if lit_content.chars().all(|c| c.is_ascii()) && !in_macro(cx, e.span) {
                            let msg = format!("calling `as_bytes()` on a string literal. \
                                               Consider using a byte string literal instead: \
                                               `b{}`",
                                               snippet(cx, args[0].span, r#""foo""#));
                            span_lint(cx, STRING_LIT_AS_BYTES, e.span, &msg);
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>