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

// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//

extern crate libc;
extern crate glob;
extern crate getopts;

#[macro_use]
extern crate uucore;

use getopts::Options;

use std::fs::File;
use std::io::{BufRead, BufReader, Write};
use std::borrow::Borrow;
use std::env;

static NAME: &'static str = "dircolors";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

mod colors;
use colors::INTERNAL_DB;

#[derive(PartialEq, Debug)]
enum OutputFmt {
    Shell,
    CShell,
    Unknown,
}

macro_rules! disp_err {
    ($($args:tt)+) => ({
        pipe_write!(&mut ::std::io::stderr(), "{}: ", NAME);
        pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
        pipe_writeln!(&mut ::std::io::stderr(), "Try '{} --help' for more information.", NAME);
    })
}

fn guess_syntax() -> OutputFmt {
    match env::var("SHELL") {
        Ok(s) => {
            if s.is_empty() {
                return OutputFmt::Unknown;
            }
            if let Some(last) = s.rsplit('/').next() {
                if last == "csh" || last == "tcsh" {
                    OutputFmt::CShell
                } else {
                    OutputFmt::Shell
                }
            } else {
                OutputFmt::Shell
            }
        }
        Err(_) => OutputFmt::Unknown,
    }
}

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

    opts.optflag("b", "sh", "output Bourne shell code to set LS_COLORS");
    opts.optflag("",
                 "bourne-shell",
                 "output Bourne shell code to set LS_COLORS");
    opts.optflag("c", "csh", "output C shell code to set LS_COLORS");
    opts.optflag("", "c-shell", "output C shell code to set LS_COLORS");
    opts.optflag("p", "print-database", "print the byte counts");

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

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

    if matches.opt_present("help") {
        println!("Usage: {} [OPTION]... [FILE]
Output commands to set the LS_COLORS environment variable.

Determine format of output:
  -b, --sh, --bourne-shell    output Bourne shell code to set LS_COLORS
  -c, --csh, --c-shell        output C shell code to set LS_COLORS
  -p, --print-database        output defaults
      --help     display this help and exit
      --version  output version information and exit

If FILE is specified, read it to determine which colors to use for which
file types and extensions.  Otherwise, a precompiled database is used.
For details on the format of these files, run 'dircolors --print-database'.",
                 NAME);
        return 0;
    }

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

    if (matches.opt_present("csh") || matches.opt_present("c-shell") ||
        matches.opt_present("sh") || matches.opt_present("bourne-shell")) &&
       matches.opt_present("print-database") {
        disp_err!("the options to output dircolors' internal database and\nto select a shell \
                   syntax are mutually exclusive");
        return 1;
    }

    if matches.opt_present("print-database") {
        if !matches.free.is_empty() {
            disp_err!("extra operand ‘{}’\nfile operands cannot be combined with \
                      --print-database (-p)",
                      matches.free[0]);
            return 1;
        }
        println!("{}", INTERNAL_DB);
        return 0;
    }

    let mut out_format = OutputFmt::Unknown;
    if matches.opt_present("csh") || matches.opt_present("c-shell") {
        out_format = OutputFmt::CShell;
    } else if matches.opt_present("sh") || matches.opt_present("bourne-shell") {
        out_format = OutputFmt::Shell;
    }

    if out_format == OutputFmt::Unknown {
        match guess_syntax() {
            OutputFmt::Unknown => {
                show_info!("no SHELL environment variable, and no shell type option given");
                return 1;
            }
            fmt => out_format = fmt,
        }
    }

    let result;
    if matches.free.is_empty() {
        result = parse(INTERNAL_DB.lines(), out_format, "")
    } else {
        if matches.free.len() > 1 {
            disp_err!("extra operand ‘{}’", matches.free[1]);
            return 1;
        }
        match File::open(matches.free[0].as_str()) {
            Ok(f) => {
                let fin = BufReader::new(f);
                result = parse(fin.lines().filter_map(|l| l.ok()),
                               out_format,
                               matches.free[0].as_str())
            }
            Err(e) => {
                show_info!("{}: {}", matches.free[0], e);
                return 1;
            }
        }
    }
    match result {
        Ok(s) => {
            println!("{}", s);
            0
        }
        Err(s) => {
            show_info!("{}", s);
            1
        }
    }
}

trait StrUtils {
    fn purify(&self) -> &Self;
    fn split_two(&self) -> (&str, &str);
    fn fnmatch(&self, pattern: &str) -> bool;
}

impl StrUtils for str {
    /// Remove comments and trim whitespaces
    fn purify(&self) -> &Self {
        let mut line = self;
        for (n, c) in self.chars().enumerate() {
            if c != '#' {
                continue;
            }

            // Ignore if '#' is at the beginning of line
            if n == 0 {
                line = &self[..0];
                break;
            }

            // Ignore the content after '#'
            // only if it is preceded by at least one whitespace
            if self.chars().nth(n - 1).unwrap().is_whitespace() {
                line = &self[..n];
            }
        }
        line.trim()
    }

    /// Like split_whitespace() but only produce 2 components
    fn split_two(&self) -> (&str, &str) {
        if let Some(b) = self.find(char::is_whitespace) {
            let key = &self[..b];
            if let Some(e) = self[b..].find(|c: char| !c.is_whitespace()) {
                (key, &self[b + e..])
            } else {
                (key, "")
            }
        } else {
            ("", "")
        }
    }

    fn fnmatch(&self, pat: &str) -> bool {
        pat.parse::<glob::Pattern>().unwrap().matches(self)
    }
}

#[derive(PartialEq)]
enum ParseState {
    Global,
    Matched,
    Continue,
    Pass,
}
use std::collections::HashMap;
fn parse<T>(lines: T, fmt: OutputFmt, fp: &str) -> Result<String, String>
    where T: IntoIterator,
          T::Item: Borrow<str>
{
    // 1440 > $(dircolors | wc -m)
    let mut result = String::with_capacity(1440);
    match fmt {
        OutputFmt::Shell => result.push_str("LS_COLORS='"),
        OutputFmt::CShell => result.push_str("setenv LS_COLORS '"),
        _ => unreachable!(),
    }

    let mut table: HashMap<&str, &str> = HashMap::with_capacity(48);
    table.insert("normal", "no");
    table.insert("norm", "no");
    table.insert("file", "fi");
    table.insert("reset", "rs");
    table.insert("dir", "di");
    table.insert("lnk", "ln");
    table.insert("link", "ln");
    table.insert("symlink", "ln");
    table.insert("orphan", "or");
    table.insert("missing", "mi");
    table.insert("fifo", "pi");
    table.insert("pipe", "pi");
    table.insert("sock", "so");
    table.insert("blk", "bd");
    table.insert("block", "bd");
    table.insert("chr", "cd");
    table.insert("char", "cd");
    table.insert("door", "do");
    table.insert("exec", "ex");
    table.insert("left", "lc");
    table.insert("leftcode", "lc");
    table.insert("right", "rc");
    table.insert("rightcode", "rc");
    table.insert("end", "ec");
    table.insert("endcode", "ec");
    table.insert("suid", "su");
    table.insert("setuid", "su");
    table.insert("sgid", "sg");
    table.insert("setgid", "sg");
    table.insert("sticky", "st");
    table.insert("other_writable", "ow");
    table.insert("owr", "ow");
    table.insert("sticky_other_writable", "tw");
    table.insert("owt", "tw");
    table.insert("capability", "ca");
    table.insert("multihardlink", "mh");
    table.insert("clrtoeol", "cl");

    let term = env::var("TERM").unwrap_or("none".to_owned());
    let term = term.as_str();

    let mut state = ParseState::Global;

    for (num, line) in lines.into_iter().enumerate() {
        let num = num + 1;
        let line = line.borrow().purify();
        if line.is_empty() {
            continue;
        }

        let (key, val) = line.split_two();
        if val.is_empty() {
            return Err(format!("{}:{}: invalid line;  missing second token", fp, num));
        }
        let lower = key.to_lowercase();

        if lower == "term" {
            if term.fnmatch(val) {
                state = ParseState::Matched;
            } else if state != ParseState::Matched {
                state = ParseState::Pass;
            }
        } else {
            if state == ParseState::Matched {
                // prevent subsequent mismatched TERM from
                // cancelling the input
                state = ParseState::Continue;
            }
            if state != ParseState::Pass {
                if key.starts_with(".") {
                    result.push_str(format!("*{}={}:", key, val).as_str());
                } else if key.starts_with("*") {
                    result.push_str(format!("{}={}:", key, val).as_str());
                } else if lower == "options" || lower == "color" || lower == "eightbit" {
                    // Slackware only. Ignore
                } else {
                    if let Some(s) = table.get(lower.as_str()) {
                        result.push_str(format!("{}={}:", s, val).as_str());
                    } else {
                        return Err(format!("{}:{}: unrecognized keyword {}", fp, num, key));
                    }
                }
            }
        }
    }

    match fmt {
        OutputFmt::Shell => result.push_str("';\nexport LS_COLORS"),
        OutputFmt::CShell => result.push('\''),
        _ => unreachable!(),
    }

    Ok(result)
}

#[test]
fn test_shell_syntax() {
    use std::env;
    let last = env!("SHELL");
    env::set_var("SHELL", "/path/csh");
    assert_eq!(OutputFmt::CShell, guess_syntax());
    env::set_var("SHELL", "csh");
    assert_eq!(OutputFmt::CShell, guess_syntax());
    env::set_var("SHELL", "/path/bash");
    assert_eq!(OutputFmt::Shell, guess_syntax());
    env::set_var("SHELL", "bash");
    assert_eq!(OutputFmt::Shell, guess_syntax());
    env::set_var("SHELL", "bash");
    assert_eq!(OutputFmt::Shell, guess_syntax());
    env::set_var("SHELL", "/asd/bar");
    assert_eq!(OutputFmt::Shell, guess_syntax());
    env::set_var("SHELL", "foo");
    assert_eq!(OutputFmt::Shell, guess_syntax());
    env::set_var("SHELL", "");
    assert_eq!(OutputFmt::Unknown, guess_syntax());
    env::remove_var("SHELL");
    assert_eq!(OutputFmt::Unknown, guess_syntax());

    env::set_var("SHELL", last);
}

#[test]
fn test_strutils() {
    let s = "  asd#zcv #hk\t\n  ";
    assert_eq!("asd#zcv", s.purify());

    let s = "con256asd";
    assert!(s.fnmatch("*[2][3-6][5-9]?sd"));

    let s = "zxc \t\nqwe jlk    hjl";
    let (k, v) = s.split_two();
    assert_eq!("zxc", k);
    assert_eq!("qwe jlk    hjl", v);
}
<commit_msg>dircolors: bypass the missing SHELL on windows<commit_after>#![crate_name = "uu_dircolors"]

// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//

extern crate libc;
extern crate glob;
extern crate getopts;

#[macro_use]
extern crate uucore;

use getopts::Options;

use std::fs::File;
use std::io::{BufRead, BufReader, Write};
use std::borrow::Borrow;
use std::env;

static NAME: &'static str = "dircolors";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

mod colors;
use colors::INTERNAL_DB;

#[derive(PartialEq, Debug)]
enum OutputFmt {
    Shell,
    CShell,
    Unknown,
}

fn guess_syntax() -> OutputFmt {
    use std::path;
    match env::var("SHELL") {
        Ok(s) => {
            if s.is_empty() {
                return OutputFmt::Unknown;
            }
            if let Some(last) = s.rsplit(path::MAIN_SEPARATOR).next() {
                if last == "csh" || last == "tcsh" {
                    OutputFmt::CShell
                } else {
                    OutputFmt::Shell
                }
            } else {
                OutputFmt::Shell
            }
        }
        Err(_) => OutputFmt::Unknown,
    }
}

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

    opts.optflag("b", "sh", "output Bourne shell code to set LS_COLORS");
    opts.optflag("",
                 "bourne-shell",
                 "output Bourne shell code to set LS_COLORS");
    opts.optflag("c", "csh", "output C shell code to set LS_COLORS");
    opts.optflag("", "c-shell", "output C shell code to set LS_COLORS");
    opts.optflag("p", "print-database", "print the byte counts");

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

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            disp_err!("{}", f);
            return 1;
        }
    };

    if matches.opt_present("help") {
        println!("Usage: {} [OPTION]... [FILE]
Output commands to set the LS_COLORS environment variable.

Determine format of output:
  -b, --sh, --bourne-shell    output Bourne shell code to set LS_COLORS
  -c, --csh, --c-shell        output C shell code to set LS_COLORS
  -p, --print-database        output defaults
      --help     display this help and exit
      --version  output version information and exit

If FILE is specified, read it to determine which colors to use for which
file types and extensions.  Otherwise, a precompiled database is used.
For details on the format of these files, run 'dircolors --print-database'.",
                 NAME);
        return 0;
    }

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

    if (matches.opt_present("csh") || matches.opt_present("c-shell") ||
        matches.opt_present("sh") || matches.opt_present("bourne-shell")) &&
       matches.opt_present("print-database") {
        disp_err!("the options to output dircolors' internal database and\nto select a shell \
                   syntax are mutually exclusive");
        return 1;
    }

    if matches.opt_present("print-database") {
        if !matches.free.is_empty() {
            disp_err!("extra operand ‘{}’\nfile operands cannot be combined with \
                      --print-database (-p)",
                      matches.free[0]);
            return 1;
        }
        println!("{}", INTERNAL_DB);
        return 0;
    }

    let mut out_format = OutputFmt::Unknown;
    if matches.opt_present("csh") || matches.opt_present("c-shell") {
        out_format = OutputFmt::CShell;
    } else if matches.opt_present("sh") || matches.opt_present("bourne-shell") {
        out_format = OutputFmt::Shell;
    }

    if out_format == OutputFmt::Unknown {
        match guess_syntax() {
            OutputFmt::Unknown => {
                show_info!("no SHELL environment variable, and no shell type option given");
                return 1;
            }
            fmt => out_format = fmt,
        }
    }

    let result;
    if matches.free.is_empty() {
        result = parse(INTERNAL_DB.lines(), out_format, "")
    } else {
        if matches.free.len() > 1 {
            disp_err!("extra operand ‘{}’", matches.free[1]);
            return 1;
        }
        match File::open(matches.free[0].as_str()) {
            Ok(f) => {
                let fin = BufReader::new(f);
                result = parse(fin.lines().filter_map(|l| l.ok()),
                               out_format,
                               matches.free[0].as_str())
            }
            Err(e) => {
                show_info!("{}: {}", matches.free[0], e);
                return 1;
            }
        }
    }
    match result {
        Ok(s) => {
            println!("{}", s);
            0
        }
        Err(s) => {
            show_info!("{}", s);
            1
        }
    }
}

trait StrUtils {
    /// Remove comments and trim whitespaces
    fn purify(&self) -> &Self;
    /// Like split_whitespace() but only produce 2 components
    fn split_two(&self) -> (&str, &str);
    fn fnmatch(&self, pattern: &str) -> bool;
}

impl StrUtils for str {
    fn purify(&self) -> &Self {
        let mut line = self;
        for (n, c) in self.chars().enumerate() {
            if c != '#' {
                continue;
            }

            // Ignore if '#' is at the beginning of line
            if n == 0 {
                line = &self[..0];
                break;
            }

            // Ignore the content after '#'
            // only if it is preceded by at least one whitespace
            if self.chars().nth(n - 1).unwrap().is_whitespace() {
                line = &self[..n];
            }
        }
        line.trim()
    }

    fn split_two(&self) -> (&str, &str) {
        if let Some(b) = self.find(char::is_whitespace) {
            let key = &self[..b];
            if let Some(e) = self[b..].find(|c: char| !c.is_whitespace()) {
                (key, &self[b + e..])
            } else {
                (key, "")
            }
        } else {
            ("", "")
        }
    }

    fn fnmatch(&self, pat: &str) -> bool {
        pat.parse::<glob::Pattern>().unwrap().matches(self)
    }
}

#[derive(PartialEq)]
enum ParseState {
    Global,
    Matched,
    Continue,
    Pass,
}
use std::collections::HashMap;
fn parse<T>(lines: T, fmt: OutputFmt, fp: &str) -> Result<String, String>
    where T: IntoIterator,
          T::Item: Borrow<str>
{
    // 1440 > $(dircolors | wc -m)
    let mut result = String::with_capacity(1440);
    match fmt {
        OutputFmt::Shell => result.push_str("LS_COLORS='"),
        OutputFmt::CShell => result.push_str("setenv LS_COLORS '"),
        _ => unreachable!(),
    }

    let mut table: HashMap<&str, &str> = HashMap::with_capacity(48);
    table.insert("normal", "no");
    table.insert("norm", "no");
    table.insert("file", "fi");
    table.insert("reset", "rs");
    table.insert("dir", "di");
    table.insert("lnk", "ln");
    table.insert("link", "ln");
    table.insert("symlink", "ln");
    table.insert("orphan", "or");
    table.insert("missing", "mi");
    table.insert("fifo", "pi");
    table.insert("pipe", "pi");
    table.insert("sock", "so");
    table.insert("blk", "bd");
    table.insert("block", "bd");
    table.insert("chr", "cd");
    table.insert("char", "cd");
    table.insert("door", "do");
    table.insert("exec", "ex");
    table.insert("left", "lc");
    table.insert("leftcode", "lc");
    table.insert("right", "rc");
    table.insert("rightcode", "rc");
    table.insert("end", "ec");
    table.insert("endcode", "ec");
    table.insert("suid", "su");
    table.insert("setuid", "su");
    table.insert("sgid", "sg");
    table.insert("setgid", "sg");
    table.insert("sticky", "st");
    table.insert("other_writable", "ow");
    table.insert("owr", "ow");
    table.insert("sticky_other_writable", "tw");
    table.insert("owt", "tw");
    table.insert("capability", "ca");
    table.insert("multihardlink", "mh");
    table.insert("clrtoeol", "cl");

    let term = env::var("TERM").unwrap_or("none".to_owned());
    let term = term.as_str();

    let mut state = ParseState::Global;

    for (num, line) in lines.into_iter().enumerate() {
        let num = num + 1;
        let line = line.borrow().purify();
        if line.is_empty() {
            continue;
        }

        let (key, val) = line.split_two();
        if val.is_empty() {
            return Err(format!("{}:{}: invalid line;  missing second token", fp, num));
        }
        let lower = key.to_lowercase();

        if lower == "term" {
            if term.fnmatch(val) {
                state = ParseState::Matched;
            } else if state != ParseState::Matched {
                state = ParseState::Pass;
            }
        } else {
            if state == ParseState::Matched {
                // prevent subsequent mismatched TERM from
                // cancelling the input
                state = ParseState::Continue;
            }
            if state != ParseState::Pass {
                if key.starts_with(".") {
                    result.push_str(format!("*{}={}:", key, val).as_str());
                } else if key.starts_with("*") {
                    result.push_str(format!("{}={}:", key, val).as_str());
                } else if lower == "options" || lower == "color" || lower == "eightbit" {
                    // Slackware only. Ignore
                } else {
                    if let Some(s) = table.get(lower.as_str()) {
                        result.push_str(format!("{}={}:", s, val).as_str());
                    } else {
                        return Err(format!("{}:{}: unrecognized keyword {}", fp, num, key));
                    }
                }
            }
        }
    }

    match fmt {
        OutputFmt::Shell => result.push_str("';\nexport LS_COLORS"),
        OutputFmt::CShell => result.push('\''),
        _ => unreachable!(),
    }

    Ok(result)
}

#[test]
fn test_shell_syntax() {
    use std::env;
    let last = env::var("SHELL");
    env::set_var("SHELL", "/path/csh");
    assert_eq!(OutputFmt::CShell, guess_syntax());
    env::set_var("SHELL", "csh");
    assert_eq!(OutputFmt::CShell, guess_syntax());
    env::set_var("SHELL", "/path/bash");
    assert_eq!(OutputFmt::Shell, guess_syntax());
    env::set_var("SHELL", "bash");
    assert_eq!(OutputFmt::Shell, guess_syntax());
    env::set_var("SHELL", "/asd/bar");
    assert_eq!(OutputFmt::Shell, guess_syntax());
    env::set_var("SHELL", "foo");
    assert_eq!(OutputFmt::Shell, guess_syntax());
    env::set_var("SHELL", "");
    assert_eq!(OutputFmt::Unknown, guess_syntax());
    env::remove_var("SHELL");
    assert_eq!(OutputFmt::Unknown, guess_syntax());

    if let Ok(s) = last {
        env::set_var("SHELL", s);
    }
}

#[test]
fn test_strutils() {
    let s = "  asd#zcv #hk\t\n  ";
    assert_eq!("asd#zcv", s.purify());

    let s = "con256asd";
    assert!(s.fnmatch("*[2][3-6][5-9]?sd"));

    let s = "zxc \t\nqwe jlk    hjl";
    let (k, v) = s.split_two();
    assert_eq!("zxc", k);
    assert_eq!("qwe jlk    hjl", v);
}
<|endoftext|>


<commit_before>use super::super::request::Request;
use super::super::response::Response;
use super::super::ingot::{Ingot, Continue, Unwind};
use super::super::anymap::AnyMap;
use super::super::alloy::Alloy;

use super::Furnace;

struct IronFurnace<Rq, Rs> {
    stack: Vec<Box<Ingot<Rq, Rs>: Send>>
}

impl<Rq: Request, Rs: Response> Clone for IronFurnace<Rq, Rs> {
    fn clone(&self) -> IronFurnace<Rq, Rs> { IronFurnace { stack: self.stack.clone() } }
}

impl<Rq: Request, Rs: Response> Furnace<Rq, Rs> for IronFurnace<Rq, Rs> {
    fn forge(&mut self, request: &mut Rq, response: &mut Rs, malloy: Option<&mut Alloy>) {
        let mut alloy = &mut AnyMap::new();

        match malloy {
            Some(a) => alloy = a,
            None => ()
        };

        let mut exit_stack = vec![];

        'enter: for ingot in self.stack.mut_iter() {
            match ingot.enter(request, response, alloy) {
                Unwind   => break 'enter,
                Continue => exit_stack.push(ingot)
            }
        }

        exit_stack.reverse();
        'exit: for ingot in exit_stack.mut_iter() {
            let _ = ingot.exit(request, response, alloy);
        }
    }
    fn smelt<I: Ingot<Rq, Rs>>(&mut self, ingot: I) {
        self.stack.push(box ingot);
    }
}

<commit_msg>(cleanup) Removed confusing variable name.<commit_after>use super::super::request::Request;
use super::super::response::Response;
use super::super::ingot::{Ingot, Continue, Unwind};
use super::super::anymap::AnyMap;
use super::super::alloy::Alloy;

use super::Furnace;

struct IronFurnace<Rq, Rs> {
    stack: Vec<Box<Ingot<Rq, Rs>: Send>>
}

impl<Rq: Request, Rs: Response> Clone for IronFurnace<Rq, Rs> {
    fn clone(&self) -> IronFurnace<Rq, Rs> { IronFurnace { stack: self.stack.clone() } }
}

impl<Rq: Request, Rs: Response> Furnace<Rq, Rs> for IronFurnace<Rq, Rs> {
    fn forge(&mut self, request: &mut Rq, response: &mut Rs, opt_alloy: Option<&mut Alloy>) {
        let mut alloy = &mut AnyMap::new();

        match opt_alloy {
            Some(a) => alloy = a,
            None => ()
        };

        let mut exit_stack = vec![];

        'enter: for ingot in self.stack.mut_iter() {
            match ingot.enter(request, response, alloy) {
                Unwind   => break 'enter,
                Continue => exit_stack.push(ingot)
            }
        }

        exit_stack.reverse();
        'exit: for ingot in exit_stack.mut_iter() {
            let _ = ingot.exit(request, response, alloy);
        }
    }
    fn smelt<I: Ingot<Rq, Rs>>(&mut self, ingot: I) {
        self.stack.push(box ingot);
    }
}

<|endoftext|>


<commit_before>use super::Projection;
use ndarray::Array1;
use geometry::{Space, RegularSpace};
use geometry::dimensions::{Dimension, Continuous, Partitioned};

pub struct UniformGrid {
    n_features: usize,
    input_space: RegularSpace<Partitioned>,
}

impl UniformGrid {
    pub fn new(input_space: RegularSpace<Partitioned>) -> Self {
        let n_features = input_space.span().into();

        UniformGrid {
            n_features: n_features,
            input_space: input_space,
        }
    }

    fn hash(&self, input: &[f64]) -> usize {
        let mut in_it = input.iter().rev();
        let mut d_it = self.input_space.iter().rev();

        let acc = d_it.next().unwrap().convert(*in_it.next().unwrap());

        d_it.zip(in_it)
            .fold(acc, |acc, (d, v)| d.convert(*v) + d.density() * acc)
    }
}

impl Projection<RegularSpace<Continuous>> for UniformGrid {
    fn project(&self, input: &Vec<f64>) -> Array1<f64> {
        let mut p = Array1::<f64>::zeros(self.n_features);
        p[self.hash(input)] = 1.0;

        p
    }

    fn dim(&self) -> usize {
        self.n_features
    }

    fn equivalent(&self, other: &Self) -> bool {
        self.dim() == other.dim()
    }
}
<commit_msg>Add tests to UniformGrid projector<commit_after>use super::Projection;
use ndarray::Array1;
use geometry::{Space, RegularSpace};
use geometry::dimensions::{Dimension, Continuous, Partitioned};

pub struct UniformGrid {
    n_features: usize,
    input_space: RegularSpace<Partitioned>,
}

impl UniformGrid {
    pub fn new(input_space: RegularSpace<Partitioned>) -> Self {
        let n_features = input_space.span().into();

        UniformGrid {
            n_features: n_features,
            input_space: input_space,
        }
    }

    fn hash(&self, input: &[f64]) -> usize {
        let mut in_it = input.iter().rev();
        let mut d_it = self.input_space.iter().rev();

        let acc = d_it.next().unwrap().convert(*in_it.next().unwrap());

        d_it.zip(in_it)
            .fold(acc, |acc, (d, v)| d.convert(*v) + d.density() * acc)
    }
}

impl Projection<RegularSpace<Continuous>> for UniformGrid {
    fn project(&self, input: &Vec<f64>) -> Array1<f64> {
        let mut p = Array1::<f64>::zeros(self.n_features);
        p[self.hash(input)] = 1.0;

        p
    }

    fn dim(&self) -> usize {
        self.n_features
    }

    fn equivalent(&self, other: &Self) -> bool {
        self.dim() == other.dim()
    }
}

#[cfg(test)]
mod tests {
    use super::{Projection, UniformGrid};
    use geometry::RegularSpace;
    use geometry::dimensions::Partitioned;

    #[test]
    fn test_1d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds);

        assert_eq!(t.dim(), 10);

        for i in 0..10 {
            let out = t.project(&vec![i as u32 as f64]).to_vec();

            let mut expected = vec![0.0; 10];
            expected[i] = 1.0;

            assert_eq!(out, expected);
        }
    }

    #[test]
    fn test_2d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds);

        assert_eq!(t.dim(), 100);

        for i in 0..10 {
            for j in 0..10 {
                let out =
                    t.project(&vec![i as u32 as f64, j as u32 as f64]).to_vec();

                let mut expected = vec![0.0; 100];
                expected[j*10 + i] = 1.0;

                assert_eq!(out, expected);
            }
        }
    }

    #[test]
    fn test_3d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));
        ds = ds.push(Partitioned::new(0.0, 10.0, 10));

        let mut t = UniformGrid::new(ds);

        assert_eq!(t.dim(), 1000);

        for i in 0..10 {
            for j in 0..10 {
                for k in 0..10 {
                    let out = t.project(&vec![i as u32 as f64,
                                              j as u32 as f64,
                                              k as u32 as f64]).to_vec();

                    let mut expected = vec![0.0; 1000];
                    expected[k*100 + j*10 + i] = 1.0;

                    assert_eq!(out, expected);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]

extern crate bytes;
#[cfg(target_os = "hermit")]
extern crate hermit_sys;
extern crate rust_tcp_io_perf;

use rust_tcp_io_perf::config;
use rust_tcp_io_perf::connection;
use rust_tcp_io_perf::print_utils;
use std::io::Read;
use std::time::Instant;

fn main() {
	let args = config::parse_config();
	let n_bytes = args.n_bytes;
	let tot_n_bytes = (n_bytes * args.n_rounds) as u64;

	let mut buf = vec![0; n_bytes];
	let mut tot_bytes: u64 = 0;

	let mut stream = connection::server_listen_and_get_first_connection(&args.port);

	let start = Instant::now();
	while tot_bytes < tot_n_bytes {
		let recv = stream.read(&mut buf).unwrap();
		if recv > 0 {
			tot_bytes += recv as u64;
		} else {
			break;
		}
	}
	let end = Instant::now();
	let duration = end.duration_since(start);

	println!("Sent in total {} Kbytes", tot_bytes / 1024);
	println!(
		"Available approximated bandwidth: {} Mbit/s",
		tot_bytes as f64 * 8.0f64 / (1024.0f64 * 1024.0f64 * duration.as_secs_f64())
	);
}
<commit_msg>improve the readability of the output<commit_after>#![allow(unused_imports)]

extern crate bytes;
#[cfg(target_os = "hermit")]
extern crate hermit_sys;
extern crate rust_tcp_io_perf;

use rust_tcp_io_perf::config;
use rust_tcp_io_perf::connection;
use rust_tcp_io_perf::print_utils;
use std::io::Read;
use std::time::Instant;

fn main() {
	let args = config::parse_config();
	let n_bytes = args.n_bytes;
	let tot_n_bytes = (n_bytes * args.n_rounds) as u64;

	let mut buf = vec![0; n_bytes];
	let mut tot_bytes: u64 = 0;

	let mut stream = connection::server_listen_and_get_first_connection(&args.port);

	let start = Instant::now();
	while tot_bytes <= tot_n_bytes {
		let recv = stream.read(&mut buf).unwrap();
		if recv > 0 {
			tot_bytes += recv as u64;
		} else {
			break;
		}
	}
	let end = Instant::now();
	let duration = end.duration_since(start);

	println!("Sent in total {} KBytes", tot_bytes / 1024);
	println!(
		"Available approximated bandwidth: {} Mbit/s",
		(tot_bytes as f64 * 8.0f64) / (1024.0f64 * 1024.0f64 * duration.as_secs_f64())
	);
}
<|endoftext|>


<commit_before>use std::{collections::VecDeque, rc::Rc};

use crate::{
    api::prelude::*, proc_macros::*, shell::prelude::WindowRequest, themes::theme_orbtk::*,
};

// --- KEYS --
pub static STYLE_WINDOW: &str = "window";
// --- KEYS --

// internal type to handle dirty widgets.
type DirtyWidgets = Vec<Entity>;

#[derive(Clone)]
enum Action {
    WindowEvent(WindowEvent),
    FocusEvent(FocusEvent),
}

// The `WindowState` handles the window events.
#[derive(Default, AsAny)]
struct WindowState {
    actions: VecDeque<Action>,
    background: Brush,
    title: String,
}

impl WindowState {
    fn push_action(&mut self, action: Action) {
        self.actions.push_front(action);
    }

    fn resize(&self, width: f64, height: f64, ctx: &mut Context) {
        Window::bounds_mut(&mut ctx.window()).set_size(width, height);
        Window::constraint_mut(&mut ctx.window()).set_size(width, height);
    }

    fn active_changed(&self, active: bool, ctx: &mut Context) {
        Window::active_set(&mut ctx.widget(), active);

        // if !active {
        //     // remove focus if the window is not active
        //     if let Some(focused_widget) = ctx.window().get::<Global>("global").focused_widget {
        //         ctx.window().get_mut::<Global>("global").focused_widget = None;
        //         if ctx.get_widget(focused_widget).has::<bool>("focused") {
        //             ctx.get_widget(focused_widget).set("focused", false);
        //             ctx.get_widget(focused_widget).update_theme_by_state(false);
        //         }
        //     }
        // }
    }

    fn request_focus(&self, entity: Entity, ctx: &mut Context) {
        let mut focus_state: FocusState = Window::focus_state_clone(&ctx.widget());
        focus_state.request_focus(entity, ctx);
        Window::focus_state_set(&mut ctx.widget(), focus_state);
    }

    fn remove_focus(&self, entity: Entity, ctx: &mut Context) {
        let mut focus_state: FocusState = Window::focus_state_clone(&ctx.widget());
        focus_state.remove_focus(entity, ctx);
        Window::focus_state_set(&mut ctx.widget(), focus_state);
    }

    fn set_background(&mut self, ctx: &mut Context) {
        let background: Brush = ctx.widget().clone("background");
        if let Brush::SolidColor(color) = background {
            ctx.render_context_2_d().set_background(color);
        };
        self.background = background;
    }
}

impl State for WindowState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.set_background(ctx);
        self.title = ctx.widget().clone("title");
    }

    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        if self.background != *Window::background_ref(&ctx.widget()) {
            self.set_background(ctx);
        }

        let window = ctx.widget();

        if !self.title.eq(Window::title_ref(&window)) {
            self.title = Window::title_clone(&window);
            ctx.send_window_request(WindowRequest::ChangeTitle(self.title.clone()));
        }

        if let Some(action) = self.actions.pop_front() {
            match action {
                Action::WindowEvent(window_event) => match window_event {
                    WindowEvent::Resize { width, height } => {
                        self.resize(width, height, ctx);
                    }
                    WindowEvent::ActiveChanged(active) => {
                        self.active_changed(active, ctx);
                    }
                    _ => {}
                },
                Action::FocusEvent(focus_event) => match focus_event {
                    FocusEvent::RequestFocus(entity) => {
                        self.request_focus(entity, ctx);
                    }
                    FocusEvent::RemoveFocus(entity) => {
                        self.remove_focus(entity, ctx);
                    }
                },
            }
        }
    }
}

widget!(
    /// The `Window` widget provides access to the properties of an application window.
    /// It also contains global properties like keyboard modifier and focused widget.
    ///
    /// **style:** `window`
    Window<WindowState>: ActivateHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the title property.
        title: String,

        /// Sets or shares the resizeable property.
        resizeable: bool,

        /// Sets or shares the property if this window should always be on top.
        always_on_top: bool,

        /// Sets or shares the flag if the window is borderless.
        borderless: bool,

        /// Sets or shares a value that describes if the current window is active.
        active: bool,

        /// Access the current keyboard state e.g. to check modifiers.
        keyboard_state: KeyboardState,

        /// Access the current window theme.
        theme: Theme,

        /// Access the current focus state.
        focus_state: FocusState,

        /// Internal property to handle dirty widgets.
        dirty_widgets: DirtyWidgets
    }
);

impl Window {
    fn on_window_event<H: Fn(&mut StatesContext, WindowEvent) -> bool + 'static>(
        self,
        handler: H,
    ) -> Self {
        self.insert_handler(WindowEventHandler {
            handler: Rc::new(handler),
        })
    }

    fn on_focus_event<H: Fn(&mut StatesContext, FocusEvent) -> bool + 'static>(
        self,
        handler: H,
    ) -> Self {
        self.insert_handler(FocusEventHandler {
            handler: Rc::new(handler),
        })
    }
}

impl Template for Window {
    fn template(self, id: Entity, _: &mut BuildContext) -> Self {
        self.name("Window")
            .background(colors::BRIGHT_GRAY_COLOR)
            .size(100.0, 100.0)
            .style(STYLE_WINDOW)
            .title("Window")
            .resizeable(false)
            .always_on_top(false)
            .on_window_event(move |ctx, event| {
                ctx.get_mut::<WindowState>(id)
                    .push_action(Action::WindowEvent(event));
                true
            })
            .on_focus_event(move |ctx, event| {
                ctx.get_mut::<WindowState>(id)
                    .push_action(Action::FocusEvent(event));
                true
            })
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        RectangleRenderObject.into()
    }

    fn layout(&self) -> Box<dyn Layout> {
        GridLayout::new().into()
    }
}
<commit_msg>✏ Fix typo in window<commit_after>use std::{collections::VecDeque, rc::Rc};

use crate::{
    api::prelude::*, proc_macros::*, shell::prelude::WindowRequest, themes::theme_orbtk::*,
};

// --- KEYS --
pub static STYLE_WINDOW: &str = "window";
// --- KEYS --

// internal type to handle dirty widgets.
type DirtyWidgets = Vec<Entity>;

#[derive(Clone)]
enum Action {
    WindowEvent(WindowEvent),
    FocusEvent(FocusEvent),
}

// The `WindowState` handles the window events.
#[derive(Default, AsAny)]
struct WindowState {
    actions: VecDeque<Action>,
    background: Brush,
    title: String,
}

impl WindowState {
    fn push_action(&mut self, action: Action) {
        self.actions.push_front(action);
    }

    fn resize(&self, width: f64, height: f64, ctx: &mut Context) {
        Window::bounds_mut(&mut ctx.window()).set_size(width, height);
        Window::constraint_mut(&mut ctx.window()).set_size(width, height);
    }

    fn active_changed(&self, active: bool, ctx: &mut Context) {
        Window::active_set(&mut ctx.widget(), active);

        // if !active {
        //     // remove focus if the window is not active
        //     if let Some(focused_widget) = ctx.window().get::<Global>("global").focused_widget {
        //         ctx.window().get_mut::<Global>("global").focused_widget = None;
        //         if ctx.get_widget(focused_widget).has::<bool>("focused") {
        //             ctx.get_widget(focused_widget).set("focused", false);
        //             ctx.get_widget(focused_widget).update_theme_by_state(false);
        //         }
        //     }
        // }
    }

    fn request_focus(&self, entity: Entity, ctx: &mut Context) {
        let mut focus_state: FocusState = Window::focus_state_clone(&ctx.widget());
        focus_state.request_focus(entity, ctx);
        Window::focus_state_set(&mut ctx.widget(), focus_state);
    }

    fn remove_focus(&self, entity: Entity, ctx: &mut Context) {
        let mut focus_state: FocusState = Window::focus_state_clone(&ctx.widget());
        focus_state.remove_focus(entity, ctx);
        Window::focus_state_set(&mut ctx.widget(), focus_state);
    }

    fn set_background(&mut self, ctx: &mut Context) {
        let background: Brush = ctx.widget().clone("background");
        if let Brush::SolidColor(color) = background {
            ctx.render_context_2_d().set_background(color);
        };
        self.background = background;
    }
}

impl State for WindowState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.set_background(ctx);
        self.title = ctx.widget().clone("title");
    }

    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        if self.background != *Window::background_ref(&ctx.widget()) {
            self.set_background(ctx);
        }

        let window = ctx.widget();

        if !self.title.eq(Window::title_ref(&window)) {
            self.title = Window::title_clone(&window);
            ctx.send_window_request(WindowRequest::ChangeTitle(self.title.clone()));
        }

        if let Some(action) = self.actions.pop_front() {
            match action {
                Action::WindowEvent(window_event) => match window_event {
                    WindowEvent::Resize { width, height } => {
                        self.resize(width, height, ctx);
                    }
                    WindowEvent::ActiveChanged(active) => {
                        self.active_changed(active, ctx);
                    }
                    _ => {}
                },
                Action::FocusEvent(focus_event) => match focus_event {
                    FocusEvent::RequestFocus(entity) => {
                        self.request_focus(entity, ctx);
                    }
                    FocusEvent::RemoveFocus(entity) => {
                        self.remove_focus(entity, ctx);
                    }
                },
            }
        }
    }
}

widget!(
    /// The `Window` widget provides access to the properties of an application window.
    /// It also contains global properties like keyboard modifier and focused widget.
    ///
    /// **style:** `window`
    Window<WindowState>: ActivateHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the title property.
        title: String,

        /// Sets or shares the resizable property.
        resizable: bool,

        /// Sets or shares the property if this window should always be on top.
        always_on_top: bool,

        /// Sets or shares the flag if the window is borderless.
        borderless: bool,

        /// Sets or shares a value that describes if the current window is active.
        active: bool,

        /// Access the current keyboard state e.g. to check modifiers.
        keyboard_state: KeyboardState,

        /// Access the current window theme.
        theme: Theme,

        /// Access the current focus state.
        focus_state: FocusState,

        /// Internal property to handle dirty widgets.
        dirty_widgets: DirtyWidgets
    }
);

impl Window {
    fn on_window_event<H: Fn(&mut StatesContext, WindowEvent) -> bool + 'static>(
        self,
        handler: H,
    ) -> Self {
        self.insert_handler(WindowEventHandler {
            handler: Rc::new(handler),
        })
    }

    fn on_focus_event<H: Fn(&mut StatesContext, FocusEvent) -> bool + 'static>(
        self,
        handler: H,
    ) -> Self {
        self.insert_handler(FocusEventHandler {
            handler: Rc::new(handler),
        })
    }

    /// Sets or shares the resizable property.
    #[inline(always)]
    #[deprecated = "Use resizable instead"]
    pub fn resizeable<P: IntoPropertySource<bool>>(self, resizeable: P) -> Self {
        self.resizable(resizeable)
    }
}

impl Template for Window {
    fn template(self, id: Entity, _: &mut BuildContext) -> Self {
        self.name("Window")
            .background(colors::BRIGHT_GRAY_COLOR)
            .size(100.0, 100.0)
            .style(STYLE_WINDOW)
            .title("Window")
            .resizable(false)
            .always_on_top(false)
            .on_window_event(move |ctx, event| {
                ctx.get_mut::<WindowState>(id)
                    .push_action(Action::WindowEvent(event));
                true
            })
            .on_focus_event(move |ctx, event| {
                ctx.get_mut::<WindowState>(id)
                    .push_action(Action::FocusEvent(event));
                true
            })
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        RectangleRenderObject.into()
    }

    fn layout(&self) -> Box<dyn Layout> {
        GridLayout::new().into()
    }
}
<|endoftext|>


<commit_before>//! These structs are a subset of the ones found in `rustc_errors::json`.
//! They are only used for deserialization of JSON output provided by libtest.

use crate::errors::{Error, ErrorKind};
use crate::runtest::ProcRes;
use serde::Deserialize;
use std::path::{Path, PathBuf};
use std::str::FromStr;

#[derive(Deserialize)]
struct Diagnostic {
    message: String,
    code: Option<DiagnosticCode>,
    level: String,
    spans: Vec<DiagnosticSpan>,
    children: Vec<Diagnostic>,
    rendered: Option<String>,
}

#[derive(Deserialize)]
struct ArtifactNotification {
    #[allow(dead_code)]
    artifact: PathBuf,
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpan {
    file_name: String,
    line_start: usize,
    line_end: usize,
    column_start: usize,
    column_end: usize,
    is_primary: bool,
    label: Option<String>,
    suggested_replacement: Option<String>,
    expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}

#[derive(Deserialize)]
struct FutureIncompatReport {
    future_incompat_report: Vec<FutureBreakageItem>,
}

#[derive(Deserialize)]
struct FutureBreakageItem {
    future_breakage_date: Option<String>,
    diagnostic: Diagnostic,
}

impl DiagnosticSpan {
    /// Returns the deepest source span in the macro call stack with a given file name.
    /// This is either the supplied span, or the span for some macro callsite that expanded to it.
    fn first_callsite_in_file(&self, file_name: &str) -> &DiagnosticSpan {
        if self.file_name == file_name {
            self
        } else {
            self.expansion
                .as_ref()
                .map(|origin| origin.span.first_callsite_in_file(file_name))
                .unwrap_or(self)
        }
    }
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpanMacroExpansion {
    /// span where macro was applied to generate this code
    span: DiagnosticSpan,

    /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
    macro_decl_name: String,
}

#[derive(Deserialize, Clone)]
struct DiagnosticCode {
    /// The code itself.
    code: String,
    /// An explanation for the code.
    explanation: Option<String>,
}

pub fn rustfix_diagnostics_only(output: &str) -> String {
    output
        .lines()
        .filter(|line| line.starts_with('{') && serde_json::from_str::<Diagnostic>(line).is_ok())
        .collect()
}

pub fn extract_rendered(output: &str) -> String {
    output
        .lines()
        .filter_map(|line| {
            if line.starts_with('{') {
                if let Ok(diagnostic) = serde_json::from_str::<Diagnostic>(line) {
                    diagnostic.rendered
                } else if let Ok(report) = serde_json::from_str::<FutureIncompatReport>(line) {
                    Some(format!(
                        "Future incompatibility report: {}",
                        report
                            .future_incompat_report
                            .into_iter()
                            .map(|item| {
                                format!(
                                    "Future breakage date: {}, diagnostic:\n{}",
                                    item.future_breakage_date.unwrap_or_else(|| "None".to_string()),
                                    item.diagnostic
                                        .rendered
                                        .unwrap_or_else(|| "Not rendered".to_string())
                                )
                            })
                            .collect::<String>()
                    ))
                } else if serde_json::from_str::<ArtifactNotification>(line).is_ok() {
                    // Ignore the notification.
                    None
                } else {
                    print!(
                        "failed to decode compiler output as json: line: {}\noutput: {}",
                        line, output
                    );
                    panic!()
                }
            } else {
                // preserve non-JSON lines, such as ICEs
                Some(format!("{}\n", line))
            }
        })
        .collect()
}

pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    output.lines().flat_map(|line| parse_line(file_name, line, output, proc_res)).collect()
}

fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    // The compiler sometimes intermingles non-JSON stuff into the
    // output.  This hack just skips over such lines. Yuck.
    if line.starts_with('{') {
        match serde_json::from_str::<Diagnostic>(line) {
            Ok(diagnostic) => {
                let mut expected_errors = vec![];
                push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name);
                expected_errors
            }
            Err(error) => {
                // Ignore the future compat report message - this is handled
                // by `extract_rendered`
                if serde_json::from_str::<FutureIncompatReport>(line).is_ok() {
                    vec![]
                } else {
                    proc_res.fatal(Some(&format!(
                        "failed to decode compiler output as json: \
                         `{}`\nline: {}\noutput: {}",
                        error, line, output
                    )));
                }
            }
        }
    } else {
        vec![]
    }
}

fn push_expected_errors(
    expected_errors: &mut Vec<Error>,
    diagnostic: &Diagnostic,
    default_spans: &[&DiagnosticSpan],
    file_name: &str,
) {
    // In case of macro expansions, we need to get the span of the callsite
    let spans_info_in_this_file: Vec<_> = diagnostic
        .spans
        .iter()
        .map(|span| (span.is_primary, span.first_callsite_in_file(file_name)))
        .filter(|(_, span)| Path::new(&span.file_name) == Path::new(&file_name))
        .collect();

    let spans_in_this_file: Vec<_> = spans_info_in_this_file.iter().map(|(_, span)| span).collect();

    let primary_spans: Vec<_> = spans_info_in_this_file
        .iter()
        .filter(|(is_primary, _)| *is_primary)
        .map(|(_, span)| span)
        .take(1) // sometimes we have more than one showing up in the json; pick first
        .cloned()
        .collect();
    let primary_spans = if primary_spans.is_empty() {
        // subdiagnostics often don't have a span of their own;
        // inherit the span from the parent in that case
        default_spans
    } else {
        &primary_spans
    };

    // We break the output into multiple lines, and then append the
    // [E123] to every line in the output. This may be overkill.  The
    // intention was to match existing tests that do things like "//|
    // found `i32` [E123]" and expect to match that somewhere, and yet
    // also ensure that `//~ ERROR E123` *always* works. The
    // assumption is that these multi-line error messages are on their
    // way out anyhow.
    let with_code = |span: &DiagnosticSpan, text: &str| {
        match diagnostic.code {
            Some(ref code) =>
            // FIXME(#33000) -- it'd be better to use a dedicated
            // UI harness than to include the line/col number like
            // this, but some current tests rely on it.
            //
            // Note: Do NOT include the filename. These can easily
            // cause false matches where the expected message
            // appears in the filename, and hence the message
            // changes but the test still passes.
            {
                format!(
                    "{}:{}: {}:{}: {} [{}]",
                    span.line_start,
                    span.column_start,
                    span.line_end,
                    span.column_end,
                    text,
                    code.code.clone()
                )
            }
            None =>
            // FIXME(#33000) -- it'd be better to use a dedicated UI harness
            {
                format!(
                    "{}:{}: {}:{}: {}",
                    span.line_start, span.column_start, span.line_end, span.column_end, text
                )
            }
        }
    };

    // Convert multi-line messages into multiple expected
    // errors. We expect to replace these with something
    // more structured shortly anyhow.
    let mut message_lines = diagnostic.message.lines();
    if let Some(first_line) = message_lines.next() {
        for span in primary_spans {
            let msg = with_code(span, first_line);
            let kind = ErrorKind::from_str(&diagnostic.level).ok();
            expected_errors.push(Error { line_num: span.line_start, kind, msg });
        }
    }
    for next_line in message_lines {
        for span in primary_spans {
            expected_errors.push(Error {
                line_num: span.line_start,
                kind: None,
                msg: with_code(span, next_line),
            });
        }
    }

    // If the message has a suggestion, register that.
    for span in primary_spans {
        if let Some(ref suggested_replacement) = span.suggested_replacement {
            for (index, line) in suggested_replacement.lines().enumerate() {
                expected_errors.push(Error {
                    line_num: span.line_start + index,
                    kind: Some(ErrorKind::Suggestion),
                    msg: line.to_string(),
                });
            }
        }
    }

    // Add notes for the backtrace
    for span in primary_spans {
        for frame in &span.expansion {
            push_backtrace(expected_errors, frame, file_name);
        }
    }

    // Add notes for any labels that appear in the message.
    for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) {
        expected_errors.push(Error {
            line_num: span.line_start,
            kind: Some(ErrorKind::Note),
            msg: span.label.clone().unwrap(),
        });
    }

    // Flatten out the children.
    for child in &diagnostic.children {
        push_expected_errors(expected_errors, child, primary_spans, file_name);
    }
}

fn push_backtrace(
    expected_errors: &mut Vec<Error>,
    expansion: &DiagnosticSpanMacroExpansion,
    file_name: &str,
) {
    if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
        expected_errors.push(Error {
            line_num: expansion.span.line_start,
            kind: Some(ErrorKind::Note),
            msg: format!("in this expansion of {}", expansion.macro_decl_name),
        });
    }

    for previous_expansion in &expansion.span.expansion {
        push_backtrace(expected_errors, previous_expansion, file_name);
    }
}
<commit_msg>Don't display empty future-compat report<commit_after>//! These structs are a subset of the ones found in `rustc_errors::json`.
//! They are only used for deserialization of JSON output provided by libtest.

use crate::errors::{Error, ErrorKind};
use crate::runtest::ProcRes;
use serde::Deserialize;
use std::path::{Path, PathBuf};
use std::str::FromStr;

#[derive(Deserialize)]
struct Diagnostic {
    message: String,
    code: Option<DiagnosticCode>,
    level: String,
    spans: Vec<DiagnosticSpan>,
    children: Vec<Diagnostic>,
    rendered: Option<String>,
}

#[derive(Deserialize)]
struct ArtifactNotification {
    #[allow(dead_code)]
    artifact: PathBuf,
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpan {
    file_name: String,
    line_start: usize,
    line_end: usize,
    column_start: usize,
    column_end: usize,
    is_primary: bool,
    label: Option<String>,
    suggested_replacement: Option<String>,
    expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}

#[derive(Deserialize)]
struct FutureIncompatReport {
    future_incompat_report: Vec<FutureBreakageItem>,
}

#[derive(Deserialize)]
struct FutureBreakageItem {
    future_breakage_date: Option<String>,
    diagnostic: Diagnostic,
}

impl DiagnosticSpan {
    /// Returns the deepest source span in the macro call stack with a given file name.
    /// This is either the supplied span, or the span for some macro callsite that expanded to it.
    fn first_callsite_in_file(&self, file_name: &str) -> &DiagnosticSpan {
        if self.file_name == file_name {
            self
        } else {
            self.expansion
                .as_ref()
                .map(|origin| origin.span.first_callsite_in_file(file_name))
                .unwrap_or(self)
        }
    }
}

#[derive(Deserialize, Clone)]
struct DiagnosticSpanMacroExpansion {
    /// span where macro was applied to generate this code
    span: DiagnosticSpan,

    /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
    macro_decl_name: String,
}

#[derive(Deserialize, Clone)]
struct DiagnosticCode {
    /// The code itself.
    code: String,
    /// An explanation for the code.
    explanation: Option<String>,
}

pub fn rustfix_diagnostics_only(output: &str) -> String {
    output
        .lines()
        .filter(|line| line.starts_with('{') && serde_json::from_str::<Diagnostic>(line).is_ok())
        .collect()
}

pub fn extract_rendered(output: &str) -> String {
    output
        .lines()
        .filter_map(|line| {
            if line.starts_with('{') {
                if let Ok(diagnostic) = serde_json::from_str::<Diagnostic>(line) {
                    diagnostic.rendered
                } else if let Ok(report) = serde_json::from_str::<FutureIncompatReport>(line) {
                    if report.future_incompat_report.is_empty() {
                        None
                    } else {
                        Some(format!(
                            "Future incompatibility report: {}",
                            report
                                .future_incompat_report
                                .into_iter()
                                .map(|item| {
                                    format!(
                                        "Future breakage date: {}, diagnostic:\n{}",
                                        item.future_breakage_date
                                            .unwrap_or_else(|| "None".to_string()),
                                        item.diagnostic
                                            .rendered
                                            .unwrap_or_else(|| "Not rendered".to_string())
                                    )
                                })
                                .collect::<String>()
                        ))
                    }
                } else if serde_json::from_str::<ArtifactNotification>(line).is_ok() {
                    // Ignore the notification.
                    None
                } else {
                    print!(
                        "failed to decode compiler output as json: line: {}\noutput: {}",
                        line, output
                    );
                    panic!()
                }
            } else {
                // preserve non-JSON lines, such as ICEs
                Some(format!("{}\n", line))
            }
        })
        .collect()
}

pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    output.lines().flat_map(|line| parse_line(file_name, line, output, proc_res)).collect()
}

fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
    // The compiler sometimes intermingles non-JSON stuff into the
    // output.  This hack just skips over such lines. Yuck.
    if line.starts_with('{') {
        match serde_json::from_str::<Diagnostic>(line) {
            Ok(diagnostic) => {
                let mut expected_errors = vec![];
                push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name);
                expected_errors
            }
            Err(error) => {
                // Ignore the future compat report message - this is handled
                // by `extract_rendered`
                if serde_json::from_str::<FutureIncompatReport>(line).is_ok() {
                    vec![]
                } else {
                    proc_res.fatal(Some(&format!(
                        "failed to decode compiler output as json: \
                         `{}`\nline: {}\noutput: {}",
                        error, line, output
                    )));
                }
            }
        }
    } else {
        vec![]
    }
}

fn push_expected_errors(
    expected_errors: &mut Vec<Error>,
    diagnostic: &Diagnostic,
    default_spans: &[&DiagnosticSpan],
    file_name: &str,
) {
    // In case of macro expansions, we need to get the span of the callsite
    let spans_info_in_this_file: Vec<_> = diagnostic
        .spans
        .iter()
        .map(|span| (span.is_primary, span.first_callsite_in_file(file_name)))
        .filter(|(_, span)| Path::new(&span.file_name) == Path::new(&file_name))
        .collect();

    let spans_in_this_file: Vec<_> = spans_info_in_this_file.iter().map(|(_, span)| span).collect();

    let primary_spans: Vec<_> = spans_info_in_this_file
        .iter()
        .filter(|(is_primary, _)| *is_primary)
        .map(|(_, span)| span)
        .take(1) // sometimes we have more than one showing up in the json; pick first
        .cloned()
        .collect();
    let primary_spans = if primary_spans.is_empty() {
        // subdiagnostics often don't have a span of their own;
        // inherit the span from the parent in that case
        default_spans
    } else {
        &primary_spans
    };

    // We break the output into multiple lines, and then append the
    // [E123] to every line in the output. This may be overkill.  The
    // intention was to match existing tests that do things like "//|
    // found `i32` [E123]" and expect to match that somewhere, and yet
    // also ensure that `//~ ERROR E123` *always* works. The
    // assumption is that these multi-line error messages are on their
    // way out anyhow.
    let with_code = |span: &DiagnosticSpan, text: &str| {
        match diagnostic.code {
            Some(ref code) =>
            // FIXME(#33000) -- it'd be better to use a dedicated
            // UI harness than to include the line/col number like
            // this, but some current tests rely on it.
            //
            // Note: Do NOT include the filename. These can easily
            // cause false matches where the expected message
            // appears in the filename, and hence the message
            // changes but the test still passes.
            {
                format!(
                    "{}:{}: {}:{}: {} [{}]",
                    span.line_start,
                    span.column_start,
                    span.line_end,
                    span.column_end,
                    text,
                    code.code.clone()
                )
            }
            None =>
            // FIXME(#33000) -- it'd be better to use a dedicated UI harness
            {
                format!(
                    "{}:{}: {}:{}: {}",
                    span.line_start, span.column_start, span.line_end, span.column_end, text
                )
            }
        }
    };

    // Convert multi-line messages into multiple expected
    // errors. We expect to replace these with something
    // more structured shortly anyhow.
    let mut message_lines = diagnostic.message.lines();
    if let Some(first_line) = message_lines.next() {
        for span in primary_spans {
            let msg = with_code(span, first_line);
            let kind = ErrorKind::from_str(&diagnostic.level).ok();
            expected_errors.push(Error { line_num: span.line_start, kind, msg });
        }
    }
    for next_line in message_lines {
        for span in primary_spans {
            expected_errors.push(Error {
                line_num: span.line_start,
                kind: None,
                msg: with_code(span, next_line),
            });
        }
    }

    // If the message has a suggestion, register that.
    for span in primary_spans {
        if let Some(ref suggested_replacement) = span.suggested_replacement {
            for (index, line) in suggested_replacement.lines().enumerate() {
                expected_errors.push(Error {
                    line_num: span.line_start + index,
                    kind: Some(ErrorKind::Suggestion),
                    msg: line.to_string(),
                });
            }
        }
    }

    // Add notes for the backtrace
    for span in primary_spans {
        for frame in &span.expansion {
            push_backtrace(expected_errors, frame, file_name);
        }
    }

    // Add notes for any labels that appear in the message.
    for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) {
        expected_errors.push(Error {
            line_num: span.line_start,
            kind: Some(ErrorKind::Note),
            msg: span.label.clone().unwrap(),
        });
    }

    // Flatten out the children.
    for child in &diagnostic.children {
        push_expected_errors(expected_errors, child, primary_spans, file_name);
    }
}

fn push_backtrace(
    expected_errors: &mut Vec<Error>,
    expansion: &DiagnosticSpanMacroExpansion,
    file_name: &str,
) {
    if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
        expected_errors.push(Error {
            line_num: expansion.span.line_start,
            kind: Some(ErrorKind::Note),
            msg: format!("in this expansion of {}", expansion.macro_decl_name),
        });
    }

    for previous_expansion in &expansion.span.expansion {
        push_backtrace(expected_errors, previous_expansion, file_name);
    }
}
<|endoftext|>


<commit_before>use crate::utils::sugg::Sugg;
use crate::utils::{
    differing_macro_contexts, is_type_diagnostic_item, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty,
    SpanlessEq,
};
use if_chain::if_chain;
use matches::matches;
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty;
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;
use syntax_pos::Symbol;

declare_clippy_lint! {
    /// **What it does:** Checks for manual swapping.
    ///
    /// **Why is this bad?** The `std::mem::swap` function exposes the intent better
    /// without deinitializing or copying either variable.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let mut a = 42;
    /// let mut b = 1337;
    ///
    /// let t = b;
    /// b = a;
    /// a = t;
    /// ```
    /// Use std::mem::swap():
    /// ```rust
    /// let mut a = 1;
    /// let mut b = 2;
    /// std::mem::swap(&mut a, &mut b);
    /// ```
    pub MANUAL_SWAP,
    complexity,
    "manual swap of two variables"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `foo = bar; bar = foo` sequences.
    ///
    /// **Why is this bad?** This looks like a failed attempt to swap.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let mut a = 1;
    /// # let mut b = 2;
    /// a = b;
    /// b = a;
    /// ```
    /// Could be written as:
    /// ```rust
    /// # let mut a = 1;
    /// # let mut b = 2;
    /// std::mem::swap(&mut a, &mut b);
    /// ```
    pub ALMOST_SWAPPED,
    correctness,
    "`foo = bar; bar = foo` sequence"
}

declare_lint_pass!(Swap => [MANUAL_SWAP, ALMOST_SWAPPED]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Swap {
    fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block) {
        check_manual_swap(cx, block);
        check_suspicious_swap(cx, block);
    }
}

/// Implementation of the `MANUAL_SWAP` lint.
fn check_manual_swap(cx: &LateContext<'_, '_>, block: &Block) {
    for w in block.stmts.windows(3) {
        if_chain! {
            // let t = foo();
            if let StmtKind::Local(ref tmp) = w[0].kind;
            if let Some(ref tmp_init) = tmp.init;
            if let PatKind::Binding(.., ident, None) = tmp.pat.kind;

            // foo() = bar();
            if let StmtKind::Semi(ref first) = w[1].kind;
            if let ExprKind::Assign(ref lhs1, ref rhs1) = first.kind;

            // bar() = t;
            if let StmtKind::Semi(ref second) = w[2].kind;
            if let ExprKind::Assign(ref lhs2, ref rhs2) = second.kind;
            if let ExprKind::Path(QPath::Resolved(None, ref rhs2)) = rhs2.kind;
            if rhs2.segments.len() == 1;

            if ident.as_str() == rhs2.segments[0].ident.as_str();
            if SpanlessEq::new(cx).ignore_fn().eq_expr(tmp_init, lhs1);
            if SpanlessEq::new(cx).ignore_fn().eq_expr(rhs1, lhs2);
            then {
                fn check_for_slice<'a>(
                    cx: &LateContext<'_, '_>,
                    lhs1: &'a Expr,
                    lhs2: &'a Expr,
                ) -> Option<(&'a Expr, &'a Expr, &'a Expr)> {
                    if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind {
                        if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind {
                            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) {
                                let ty = walk_ptrs_ty(cx.tables.expr_ty(lhs1));

                                if matches!(ty.kind, ty::Slice(_)) ||
                                    matches!(ty.kind, ty::Array(_, _)) ||
                                    is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type")) ||
                                    match_type(cx, ty, &paths::VEC_DEQUE) {
                                        return Some((lhs1, idx1, idx2));
                                }
                            }
                        }
                    }

                    None
                }

                if let ExprKind::Field(ref lhs1, _) = lhs1.kind {
                    if let ExprKind::Field(ref lhs2, _) = lhs2.kind {
                        if lhs1.hir_id.owner_def_id() == lhs2.hir_id.owner_def_id() {
                            return;
                        }
                    }
                }

                let (replace, what, sugg) = if let Some((slice, idx1, idx2)) = check_for_slice(cx, lhs1, lhs2) {
                    if let Some(slice) = Sugg::hir_opt(cx, slice) {
                        (false,
                         format!(" elements of `{}`", slice),
                         format!("{}.swap({}, {})",
                                 slice.maybe_par(),
                                 snippet(cx, idx1.span, ".."),
                                 snippet(cx, idx2.span, "..")))
                    } else {
                        (false, String::new(), String::new())
                    }
                } else if let (Some(first), Some(second)) = (Sugg::hir_opt(cx, lhs1), Sugg::hir_opt(cx, rhs1)) {
                    (true, format!(" `{}` and `{}`", first, second),
                        format!("std::mem::swap({}, {})", first.mut_addr(), second.mut_addr()))
                } else {
                    (true, String::new(), String::new())
                };

                let span = w[0].span.to(second.span);

                span_lint_and_then(cx,
                                   MANUAL_SWAP,
                                   span,
                                   &format!("this looks like you are swapping{} manually", what),
                                   |db| {
                                       if !sugg.is_empty() {
                                           db.span_suggestion(
                                               span,
                                               "try",
                                               sugg,
                                               Applicability::Unspecified,
                                           );

                                           if replace {
                                               db.note("or maybe you should use `std::mem::replace`?");
                                           }
                                       }
                                   });
            }
        }
    }
}

/// Implementation of the `ALMOST_SWAPPED` lint.
fn check_suspicious_swap(cx: &LateContext<'_, '_>, block: &Block) {
    for w in block.stmts.windows(2) {
        if_chain! {
            if let StmtKind::Semi(ref first) = w[0].kind;
            if let StmtKind::Semi(ref second) = w[1].kind;
            if !differing_macro_contexts(first.span, second.span);
            if let ExprKind::Assign(ref lhs0, ref rhs0) = first.kind;
            if let ExprKind::Assign(ref lhs1, ref rhs1) = second.kind;
            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs0, rhs1);
            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, rhs0);
            then {
                let lhs0 = Sugg::hir_opt(cx, lhs0);
                let rhs0 = Sugg::hir_opt(cx, rhs0);
                let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) {
                    (
                        format!(" `{}` and `{}`", first, second),
                        first.mut_addr().to_string(),
                        second.mut_addr().to_string(),
                    )
                } else {
                    (String::new(), String::new(), String::new())
                };

                let span = first.span.to(second.span);

                span_lint_and_then(cx,
                                   ALMOST_SWAPPED,
                                   span,
                                   &format!("this looks like you are trying to swap{}", what),
                                   |db| {
                                       if !what.is_empty() {
                                           db.span_suggestion(
                                               span,
                                               "try",
                                               format!(
                                                   "std::mem::swap({}, {})",
                                                   lhs,
                                                   rhs,
                                               ),
                                               Applicability::MaybeIncorrect,
                                           );
                                           db.note("or maybe you should use `std::mem::replace`?");
                                       }
                                   });
            }
        }
    }
}
<commit_msg>Fix FP in manual_swap lint with slice-like types<commit_after>use crate::utils::sugg::Sugg;
use crate::utils::{
    differing_macro_contexts, is_type_diagnostic_item, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty,
    SpanlessEq,
};
use if_chain::if_chain;
use matches::matches;
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::ty;
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;
use syntax_pos::Symbol;

declare_clippy_lint! {
    /// **What it does:** Checks for manual swapping.
    ///
    /// **Why is this bad?** The `std::mem::swap` function exposes the intent better
    /// without deinitializing or copying either variable.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// let mut a = 42;
    /// let mut b = 1337;
    ///
    /// let t = b;
    /// b = a;
    /// a = t;
    /// ```
    /// Use std::mem::swap():
    /// ```rust
    /// let mut a = 1;
    /// let mut b = 2;
    /// std::mem::swap(&mut a, &mut b);
    /// ```
    pub MANUAL_SWAP,
    complexity,
    "manual swap of two variables"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `foo = bar; bar = foo` sequences.
    ///
    /// **Why is this bad?** This looks like a failed attempt to swap.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let mut a = 1;
    /// # let mut b = 2;
    /// a = b;
    /// b = a;
    /// ```
    /// Could be written as:
    /// ```rust
    /// # let mut a = 1;
    /// # let mut b = 2;
    /// std::mem::swap(&mut a, &mut b);
    /// ```
    pub ALMOST_SWAPPED,
    correctness,
    "`foo = bar; bar = foo` sequence"
}

declare_lint_pass!(Swap => [MANUAL_SWAP, ALMOST_SWAPPED]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Swap {
    fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block) {
        check_manual_swap(cx, block);
        check_suspicious_swap(cx, block);
    }
}

/// Implementation of the `MANUAL_SWAP` lint.
fn check_manual_swap(cx: &LateContext<'_, '_>, block: &Block) {
    for w in block.stmts.windows(3) {
        if_chain! {
            // let t = foo();
            if let StmtKind::Local(ref tmp) = w[0].kind;
            if let Some(ref tmp_init) = tmp.init;
            if let PatKind::Binding(.., ident, None) = tmp.pat.kind;

            // foo() = bar();
            if let StmtKind::Semi(ref first) = w[1].kind;
            if let ExprKind::Assign(ref lhs1, ref rhs1) = first.kind;

            // bar() = t;
            if let StmtKind::Semi(ref second) = w[2].kind;
            if let ExprKind::Assign(ref lhs2, ref rhs2) = second.kind;
            if let ExprKind::Path(QPath::Resolved(None, ref rhs2)) = rhs2.kind;
            if rhs2.segments.len() == 1;

            if ident.as_str() == rhs2.segments[0].ident.as_str();
            if SpanlessEq::new(cx).ignore_fn().eq_expr(tmp_init, lhs1);
            if SpanlessEq::new(cx).ignore_fn().eq_expr(rhs1, lhs2);
            then {
                if let ExprKind::Field(ref lhs1, _) = lhs1.kind {
                    if let ExprKind::Field(ref lhs2, _) = lhs2.kind {
                        if lhs1.hir_id.owner_def_id() == lhs2.hir_id.owner_def_id() {
                            return;
                        }
                    }
                }

                let slice = check_for_slice(cx, lhs1, lhs2);

                let (replace, what, sugg) = if let Slice::NotSwappable = slice {
                    return;
                } else if let Slice::Swappable(slice, idx1, idx2) = slice {
                    if let Some(slice) = Sugg::hir_opt(cx, slice) {
                        (false,
                         format!(" elements of `{}`", slice),
                         format!("{}.swap({}, {})",
                                 slice.maybe_par(),
                                 snippet(cx, idx1.span, ".."),
                                 snippet(cx, idx2.span, "..")))
                    } else {
                        (false, String::new(), String::new())
                    }
                } else if let (Some(first), Some(second)) = (Sugg::hir_opt(cx, lhs1), Sugg::hir_opt(cx, rhs1)) {
                    (true, format!(" `{}` and `{}`", first, second),
                        format!("std::mem::swap({}, {})", first.mut_addr(), second.mut_addr()))
                } else {
                    (true, String::new(), String::new())
                };

                let span = w[0].span.to(second.span);

                span_lint_and_then(cx,
                                   MANUAL_SWAP,
                                   span,
                                   &format!("this looks like you are swapping{} manually", what),
                                   |db| {
                                       if !sugg.is_empty() {
                                           db.span_suggestion(
                                               span,
                                               "try",
                                               sugg,
                                               Applicability::Unspecified,
                                           );

                                           if replace {
                                               db.note("or maybe you should use `std::mem::replace`?");
                                           }
                                       }
                                   });
            }
        }
    }
}

enum Slice<'a> {
    /// `slice.swap(idx1, idx2)` can be used
    ///
    /// ## Example
    ///
    /// ```rust
    /// let t = a[1];
    /// a[1] = a[0];
    /// a[0] = t;
    /// // can be written as
    /// a.swap(0, 1);
    /// ```
    Swappable(&'a Expr, &'a Expr, &'a Expr),
    /// The `swap` function cannot be used.
    ///
    /// ## Example
    ///
    /// ```rust
    /// let t = a[0][1];
    /// a[0][1] = a[1][0];
    /// a[1][0] = t;
    /// ```
    NotSwappable,
    /// Not a slice
    None,
}

/// Checks if both expressions are index operations into "slice-like" types.
fn check_for_slice<'a>(cx: &LateContext<'_, '_>, lhs1: &'a Expr, lhs2: &'a Expr) -> Slice<'a> {
    if let ExprKind::Index(ref lhs1, ref idx1) = lhs1.kind {
        if let ExprKind::Index(ref lhs2, ref idx2) = lhs2.kind {
            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) {
                let ty = walk_ptrs_ty(cx.tables.expr_ty(lhs1));

                if matches!(ty.kind, ty::Slice(_))
                    || matches!(ty.kind, ty::Array(_, _))
                    || is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type"))
                    || match_type(cx, ty, &paths::VEC_DEQUE)
                {
                    return Slice::Swappable(lhs1, idx1, idx2);
                }
            } else {
                return Slice::NotSwappable;
            }
        }
    }

    Slice::None
}

/// Implementation of the `ALMOST_SWAPPED` lint.
fn check_suspicious_swap(cx: &LateContext<'_, '_>, block: &Block) {
    for w in block.stmts.windows(2) {
        if_chain! {
            if let StmtKind::Semi(ref first) = w[0].kind;
            if let StmtKind::Semi(ref second) = w[1].kind;
            if !differing_macro_contexts(first.span, second.span);
            if let ExprKind::Assign(ref lhs0, ref rhs0) = first.kind;
            if let ExprKind::Assign(ref lhs1, ref rhs1) = second.kind;
            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs0, rhs1);
            if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, rhs0);
            then {
                let lhs0 = Sugg::hir_opt(cx, lhs0);
                let rhs0 = Sugg::hir_opt(cx, rhs0);
                let (what, lhs, rhs) = if let (Some(first), Some(second)) = (lhs0, rhs0) {
                    (
                        format!(" `{}` and `{}`", first, second),
                        first.mut_addr().to_string(),
                        second.mut_addr().to_string(),
                    )
                } else {
                    (String::new(), String::new(), String::new())
                };

                let span = first.span.to(second.span);

                span_lint_and_then(cx,
                                   ALMOST_SWAPPED,
                                   span,
                                   &format!("this looks like you are trying to swap{}", what),
                                   |db| {
                                       if !what.is_empty() {
                                           db.span_suggestion(
                                               span,
                                               "try",
                                               format!(
                                                   "std::mem::swap({}, {})",
                                                   lhs,
                                                   rhs,
                                               ),
                                               Applicability::MaybeIncorrect,
                                           );
                                           db.note("or maybe you should use `std::mem::replace`?");
                                       }
                                   });
            }
        }
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::hashmap::HashMap;
use core_types::{
  Size2,
  Int,
  UnitId,
  PlayerId,
  MapPos,
};

pub enum Command {
  CommandMove(UnitId, MapPos),
  CommandEndTurn,
}

pub enum EventView {
  EventViewMove(UnitId, ~[MapPos]),
  EventViewEndTurn(PlayerId, PlayerId), // old_id, new_id
}

pub struct Player {
  id: PlayerId,
}

pub struct Unit {
  id: UnitId,
  pos: MapPos,
}

pub struct Core<'a> {
  units: ~[Unit],
  players: ~[Player],
  current_player_id: PlayerId,
  event_list: ~[~Event],
  event_view_lists: HashMap<PlayerId, ~[EventView]>,
  map_size: Size2<Int>,
}

fn get_event_view_lists() -> HashMap<PlayerId, ~[EventView]> {
  let mut map = HashMap::new();
  map.insert(0 as PlayerId, ~[]);
  map.insert(1 as PlayerId, ~[]);
  map
}

impl<'a> Core<'a> {
  pub fn new() -> Core {
    Core {
      units: ~[],
      players: ~[Player{id: 0}, Player{id: 1}],
      current_player_id: 0,
      event_list: ~[],
      event_view_lists: get_event_view_lists(),
      map_size: Size2{x: 4, y: 8},
    }
  }

  pub fn get_event_view(&mut self) -> Option<EventView> {
    let list = self.event_view_lists.get_mut(&self.current_player_id);
    list.shift()
  }

  fn id_to_unit_mut_opt(&'a mut self, id: UnitId) -> Option<&'a mut Unit> {
    self.units.mut_iter().find(|u| u.id == id)
  }

  fn id_to_unit_mut(&'a mut self, id: UnitId) -> &'a mut Unit {
    match self.id_to_unit_mut_opt(id) {
      Some(unit) => unit,
      None => fail!("Bad unit id: {}", id),
    }
  }

  fn id_to_unit_opt(&'a self, id: UnitId) -> Option<&'a Unit> {
    self.units.iter().find(|u| u.id == id)
  }

  fn id_to_unit(&'a self, id: UnitId) -> &'a Unit {
    match self.id_to_unit_opt(id) {
      Some(unit) => unit,
      None => fail!("Bad unit id: {}", id),
    }
  }

  // TODO: Remove or make private
  pub fn unit_at_opt(&'a self, pos: MapPos) -> Option<&'a Unit> {
    self.units.iter().find(|u| u.pos == pos)
  }

  fn command_to_event(&self, command: Command) -> ~Event {
    match command {
      CommandEndTurn => {
        EventEndTurn::new(self) as ~Event
      },
      CommandMove(unit_id, destination) => {
        EventMove::new(self, unit_id, destination) as ~Event
      },
    }
  }

  pub fn do_command(&mut self, command: Command) {
    let event = self.command_to_event(command);
    self.event_list.push(event);
    self.make_event_views();
  }

  fn make_event_views(&mut self) {
    while self.event_list.len() != 0 {
      let event = self.event_list.pop().unwrap();
      event.apply(self);
      for player in self.players.iter() {
        let event_view_list = self.event_view_lists.get_mut(&player.id);
        event_view_list.push(event.get_view());
      }
    }
  }
}

trait Event {
  fn apply(&self, core: &mut Core);
  fn get_view(&self) -> EventView;
  // TODO: fn is_visible(&self) -> Bool;
}

struct EventMove {
  unit_id: UnitId,
  path: ~[MapPos],
}

impl EventMove {
  fn new(core: &Core, unit_id: UnitId, destination: MapPos) -> ~EventMove {
    let start_pos = core.id_to_unit(unit_id).pos;
    ~EventMove {
      path: ~[start_pos, destination],
      unit_id: unit_id,
    }
  }
}

impl Event for EventMove {
  fn get_view(&self) -> EventView {
    EventViewMove(self.unit_id, self.path.clone())
  }

  fn apply(&self, core: &mut Core) {
    let unit = core.id_to_unit_mut(self.unit_id);
    unit.pos = *self.path.last().unwrap();
  }
}

struct EventEndTurn {
  old_id: PlayerId,
  new_id: PlayerId,
}

impl EventEndTurn {
  fn new(core: &Core) -> ~EventEndTurn {
    let old_id = core.current_player_id;
    let max_id = core.players.len() as Int;
    let new_id = if old_id + 1 == max_id { 0 } else { old_id + 1 };
    ~EventEndTurn{old_id: old_id, new_id: new_id}
  }
}

impl Event for EventEndTurn {
  fn get_view(&self) -> EventView {
    EventViewEndTurn(self.old_id, self.new_id)
  }

  fn apply(&self, core: &mut Core) {
    // core.deselected_any_units();
    for player in core.players.iter() {
      if player.id == self.new_id {
        if core.current_player_id == self.old_id {
          core.current_player_id = player.id;
        }
        return;
      }
    }
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>Core: Event -> CoreEvent<commit_after>// See LICENSE file for copyright and license details.

use std::hashmap::HashMap;
use core_types::{
  Size2,
  Int,
  UnitId,
  PlayerId,
  MapPos,
};

pub enum Command {
  CommandMove(UnitId, MapPos),
  CommandEndTurn,
}

pub enum EventView {
  EventViewMove(UnitId, ~[MapPos]),
  EventViewEndTurn(PlayerId, PlayerId), // old_id, new_id
}

pub struct Player {
  id: PlayerId,
}

pub struct Unit {
  id: UnitId,
  pos: MapPos,
}

pub struct Core<'a> {
  units: ~[Unit],
  players: ~[Player],
  current_player_id: PlayerId,
  core_event_list: ~[~CoreEvent],
  event_view_lists: HashMap<PlayerId, ~[EventView]>,
  map_size: Size2<Int>,
}

fn get_event_view_lists() -> HashMap<PlayerId, ~[EventView]> {
  let mut map = HashMap::new();
  map.insert(0 as PlayerId, ~[]);
  map.insert(1 as PlayerId, ~[]);
  map
}

impl<'a> Core<'a> {
  pub fn new() -> Core {
    Core {
      units: ~[],
      players: ~[Player{id: 0}, Player{id: 1}],
      current_player_id: 0,
      core_event_list: ~[],
      event_view_lists: get_event_view_lists(),
      map_size: Size2{x: 4, y: 8},
    }
  }

  pub fn get_event_view(&mut self) -> Option<EventView> {
    let list = self.event_view_lists.get_mut(&self.current_player_id);
    list.shift()
  }

  fn id_to_unit_mut_opt(&'a mut self, id: UnitId) -> Option<&'a mut Unit> {
    self.units.mut_iter().find(|u| u.id == id)
  }

  fn id_to_unit_mut(&'a mut self, id: UnitId) -> &'a mut Unit {
    match self.id_to_unit_mut_opt(id) {
      Some(unit) => unit,
      None => fail!("Bad unit id: {}", id),
    }
  }

  fn id_to_unit_opt(&'a self, id: UnitId) -> Option<&'a Unit> {
    self.units.iter().find(|u| u.id == id)
  }

  fn id_to_unit(&'a self, id: UnitId) -> &'a Unit {
    match self.id_to_unit_opt(id) {
      Some(unit) => unit,
      None => fail!("Bad unit id: {}", id),
    }
  }

  // TODO: Remove or make private
  pub fn unit_at_opt(&'a self, pos: MapPos) -> Option<&'a Unit> {
    self.units.iter().find(|u| u.pos == pos)
  }

  fn command_to_core_event(&self, command: Command) -> ~CoreEvent {
    match command {
      CommandEndTurn => {
        CoreEventEndTurn::new(self) as ~CoreEvent
      },
      CommandMove(unit_id, destination) => {
        CoreEventMove::new(self, unit_id, destination) as ~CoreEvent
      },
    }
  }

  pub fn do_command(&mut self, command: Command) {
    let core_event = self.command_to_core_event(command);
    self.core_event_list.push(core_event);
    self.make_event_views();
  }

  fn make_event_views(&mut self) {
    while self.core_event_list.len() != 0 {
      let event = self.core_event_list.pop().unwrap();
      event.apply(self);
      for player in self.players.iter() {
        let event_view_list = self.event_view_lists.get_mut(&player.id);
        event_view_list.push(event.get_view());
      }
    }
  }
}

trait CoreEvent {
  fn apply(&self, core: &mut Core);
  fn get_view(&self) -> EventView;
  // TODO: fn is_visible(&self) -> Bool;
}

struct CoreEventMove {
  unit_id: UnitId,
  path: ~[MapPos],
}

impl CoreEventMove {
  fn new(core: &Core, unit_id: UnitId, destination: MapPos) -> ~CoreEventMove {
    let start_pos = core.id_to_unit(unit_id).pos;
    ~CoreEventMove {
      path: ~[start_pos, destination],
      unit_id: unit_id,
    }
  }
}

impl CoreEvent for CoreEventMove {
  fn get_view(&self) -> EventView {
    EventViewMove(self.unit_id, self.path.clone())
  }

  fn apply(&self, core: &mut Core) {
    let unit = core.id_to_unit_mut(self.unit_id);
    unit.pos = *self.path.last().unwrap();
  }
}

struct CoreEventEndTurn {
  old_id: PlayerId,
  new_id: PlayerId,
}

impl CoreEventEndTurn {
  fn new(core: &Core) -> ~CoreEventEndTurn {
    let old_id = core.current_player_id;
    let max_id = core.players.len() as Int;
    let new_id = if old_id + 1 == max_id { 0 } else { old_id + 1 };
    ~CoreEventEndTurn{old_id: old_id, new_id: new_id}
  }
}

impl CoreEvent for CoreEventEndTurn {
  fn get_view(&self) -> EventView {
    EventViewEndTurn(self.old_id, self.new_id)
  }

  fn apply(&self, core: &mut Core) {
    // core.deselected_any_units();
    for player in core.players.iter() {
      if player.id == self.new_id {
        if core.current_player_id == self.old_id {
          core.current_player_id = player.id;
        }
        return;
      }
    }
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>


<commit_before>// Menu for a text-based adventure game.
// (Also learn how to import/use code from another file!)

use std::io::{self, BufRead};

#[derive(Clone)]
struct MenuOption {
  selector: char,
  description: &'static str,
}

static OPTIONS : [MenuOption; 3] = [MenuOption { selector: 'n', description: "New Game", },
                                    MenuOption { selector: 'l', description: "Load Game", },
                                    MenuOption { selector: 'q', description: "Quit", }];

pub fn display_menu() {
  let mut has_selected_option: bool = false;

  while !has_selected_option {
    println!("  Menu  ");
    println!("--------");
    for i in 0..OPTIONS.len() {
      display_menu_option(OPTIONS[i].clone());
  }
    has_selected_option = read_menu_option();
  }
}

fn display_menu_option(opt:MenuOption) {
  println!(" {sel} - {desc} ", sel=opt.selector, desc=opt.description)
}

fn read_menu_option() -> bool {
  let mut opt = String::new();
  let stdin = io::stdin();
  stdin.lock().read_line(&mut opt).unwrap();

  for i in 0..OPTIONS.len() {
    if opt == OPTIONS[i].clone().selector.to_string() {
      return true;
    }
  }

  return false;
}
<commit_msg>fix matching through truncate opt to one character<commit_after>// Menu for a text-based adventure game.
// (Also learn how to import/use code from another file!)

use std::io::{self, BufRead};

#[derive(Clone)]
struct MenuOption {
  selector: char,
  description: &'static str,
}

static OPTIONS : [MenuOption; 3] = [MenuOption { selector: 'n', description: "New Game", },
                                    MenuOption { selector: 'l', description: "Load Game", },
                                    MenuOption { selector: 'q', description: "Quit", }];

pub fn display_menu() {
  let mut has_selected_option: bool = false;

  while !has_selected_option {
    println!("  Menu  ");
    println!("--------");
    for i in 0..OPTIONS.len() {
      display_menu_option(OPTIONS[i].clone());
  }
    has_selected_option = read_menu_option();
  }
}

fn display_menu_option(opt:MenuOption) {
  println!(" {sel} - {desc} ", sel=opt.selector, desc=opt.description)
}

fn read_menu_option() -> bool {
  let mut opt = String::new();
  let stdin = io::stdin();
  stdin.lock().read_line(&mut opt).unwrap();
  opt.truncate(1);

  for i in 0..OPTIONS.len() {
    if opt == OPTIONS[i].clone().selector.to_string() {
      return true;
    }
  }

  return false;
}
<|endoftext|>