<commit_before>use cargo::core::Workspace;
use cargo::ops;
use cargo::util::{CliResult, Config};
use cargo::util::important_paths::{find_root_manifest_for_wd};

#[derive(RustcDecodable)]
pub struct Options {
    flag_verbose: u32,
    flag_quiet: Option<bool>,
    flag_color: Option<String>,
    flag_manifest_path: Option<String>,
    flag_frozen: bool,
    flag_locked: bool,
    arg_spec: Option<String>,
}

pub const USAGE: &'static str = "
Print a fully qualified package specification

Usage:
    cargo pkgid [options] [<spec>]

Options:
    -h, --help               Print this message
    --manifest-path PATH     Path to the manifest to the package to clean
    -v, --verbose ...        Use verbose output
    -q, --quiet              No output printed to stdout
    --color WHEN             Coloring: auto, always, never
    --frozen                 Require Cargo.lock and cache are up to date
    --locked                 Require Cargo.lock is up to date

Given a <spec> argument, print out the fully qualified package id specifier.
This command will generate an error if <spec> is ambiguous as to which package
it refers to in the dependency graph. If no <spec> is given, then the pkgid for
the local package is printed.

This command requires that a lockfile is available and dependencies have been
fetched.

Example Package IDs

           pkgid                  |  name  |  version  |          url
    |-----------------------------|--------|-----------|---------------------|
     foo                          | foo    | *         | *
     foo:1.2.3                    | foo    | 1.2.3     | *
     crates.io/foo                | foo    | *         | *://crates.io/foo
     crates.io/foo#1.2.3          | foo    | 1.2.3     | *://crates.io/foo
     crates.io/bar#foo:1.2.3      | foo    | 1.2.3     | *://crates.io/bar
     http://crates.io/foo#1.2.3   | foo    | 1.2.3     | http://crates.io/foo

";

pub fn execute(options: Options,
               config: &Config) -> CliResult<Option<()>> {
    try!(config.configure(options.flag_verbose,
                          options.flag_quiet,
                          &options.flag_color,
                          options.flag_frozen,
                          options.flag_locked));
    let root = try!(find_root_manifest_for_wd(options.flag_manifest_path.clone(), config.cwd()));
    let ws = try!(Workspace::new(&root, config));

    let spec = options.arg_spec.as_ref().map(|s| &s[..]);
    let spec = try!(ops::pkgid(&ws, spec));
    println!("{}", spec);
    Ok(None)
}

<commit_msg>pkgid: add the -p flag as the output suggests<commit_after>use cargo::core::Workspace;
use cargo::ops;
use cargo::util::{CliResult, Config};
use cargo::util::important_paths::{find_root_manifest_for_wd};

#[derive(RustcDecodable)]
pub struct Options {
    flag_verbose: u32,
    flag_quiet: Option<bool>,
    flag_color: Option<String>,
    flag_manifest_path: Option<String>,
    flag_frozen: bool,
    flag_locked: bool,
    flag_package: Option<String>,
    arg_spec: Option<String>,
}

pub const USAGE: &'static str = "
Print a fully qualified package specification

Usage:
    cargo pkgid [options] [<spec>]

Options:
    -h, --help               Print this message
    -p SPEC, --package SPEC  Argument to get the package id specifier for
    --manifest-path PATH     Path to the manifest to the package to clean
    -v, --verbose ...        Use verbose output
    -q, --quiet              No output printed to stdout
    --color WHEN             Coloring: auto, always, never
    --frozen                 Require Cargo.lock and cache are up to date
    --locked                 Require Cargo.lock is up to date

Given a <spec> argument, print out the fully qualified package id specifier.
This command will generate an error if <spec> is ambiguous as to which package
it refers to in the dependency graph. If no <spec> is given, then the pkgid for
the local package is printed.

This command requires that a lockfile is available and dependencies have been
fetched.

Example Package IDs

           pkgid                  |  name  |  version  |          url
    |-----------------------------|--------|-----------|---------------------|
     foo                          | foo    | *         | *
     foo:1.2.3                    | foo    | 1.2.3     | *
     crates.io/foo                | foo    | *         | *://crates.io/foo
     crates.io/foo#1.2.3          | foo    | 1.2.3     | *://crates.io/foo
     crates.io/bar#foo:1.2.3      | foo    | 1.2.3     | *://crates.io/bar
     http://crates.io/foo#1.2.3   | foo    | 1.2.3     | http://crates.io/foo

";

pub fn execute(options: Options,
               config: &Config) -> CliResult<Option<()>> {
    try!(config.configure(options.flag_verbose,
                          options.flag_quiet,
                          &options.flag_color,
                          options.flag_frozen,
                          options.flag_locked));
    let root = try!(find_root_manifest_for_wd(options.flag_manifest_path.clone(), config.cwd()));
    let ws = try!(Workspace::new(&root, config));

    let spec = if options.arg_spec.is_some() {
        options.arg_spec
    } else if options.flag_package.is_some() {
        options.flag_package
    } else {
        None
    };
    let spec = spec.as_ref().map(|s| &s[..]);
    let spec = try!(ops::pkgid(&ws, spec));
    println!("{}", spec);
    Ok(None)
}

<|endoftext|>


<commit_before>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use super::{
    machine::{self, Context},
    ProgressReporter, Reboot, Result, State, StateChangeImpl,
};
use crate::{
    firmware::installation_set,
    object::{self, Installer},
    update_package::{UpdatePackage, UpdatePackageExt},
};
use slog_scope::info;

#[derive(Debug)]
pub(super) struct Install {
    pub(super) update_package: UpdatePackage,
}

impl ProgressReporter for Install {
    fn package_uid(&self) -> String {
        self.update_package.package_uid()
    }

    fn report_enter_state_name(&self) -> &'static str {
        "installing"
    }

    fn report_leave_state_name(&self) -> &'static str {
        "installed"
    }
}

#[async_trait::async_trait(?Send)]
impl StateChangeImpl for Install {
    fn name(&self) -> &'static str {
        "install"
    }

    async fn handle(mut self, context: &mut Context) -> Result<(State, machine::StepTransition)> {
        let package_uid = self.update_package.package_uid();
        info!("installing update: {}", &package_uid);

        let installation_set = context.runtime_settings.get_inactive_installation_set()?;
        info!("using installation set as target {}", installation_set);

        // FIXME: What is missing:
        //
        // - verify if the object needs to be installed, accordingly to the install if
        //   different rule.

        let objs = self.update_package.objects_mut(installation_set);
        objs.iter().try_for_each(object::Installer::check_requirements)?;
        objs.iter_mut().try_for_each(|obj| obj.install(&context.settings.update.download_dir))?;

        // Avoid installing same package twice.
        context.runtime_settings.set_applied_package_uid(&package_uid)?;

        // Set upgrading to the new installation set
        context.runtime_settings.set_upgrading_to(installation_set)?;

        // Swap installation set so it is used next device boot.
        installation_set::swap_active()?;
        info!("swapping active installation set");

        info!("update installed successfully");
        Ok((
            State::Reboot(Reboot { update_package: self.update_package }),
            machine::StepTransition::Immediate,
        ))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::update_package::tests::get_update_package;
    use pretty_assertions::assert_eq;

    #[async_std::test]
    async fn has_package_uid_if_succeed() {
        let setup = crate::tests::TestEnvironment::build().finish();
        let mut context = setup.gen_context();
        let state = Install { update_package: get_update_package() };

        let machine = State::Install(state).move_to_next_state(&mut context).await.unwrap().0;

        match machine {
            State::Reboot(_) => assert_eq!(
                context.runtime_settings.applied_package_uid(),
                Some(get_update_package().package_uid())
            ),
            s => panic!("Invalid success: {:?}", s),
        }
    }
}
<commit_msg>updatehub: Remove outdated FIXME about install if different<commit_after>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use super::{
    machine::{self, Context},
    ProgressReporter, Reboot, Result, State, StateChangeImpl,
};
use crate::{
    firmware::installation_set,
    object::{self, Installer},
    update_package::{UpdatePackage, UpdatePackageExt},
};
use slog_scope::info;

#[derive(Debug)]
pub(super) struct Install {
    pub(super) update_package: UpdatePackage,
}

impl ProgressReporter for Install {
    fn package_uid(&self) -> String {
        self.update_package.package_uid()
    }

    fn report_enter_state_name(&self) -> &'static str {
        "installing"
    }

    fn report_leave_state_name(&self) -> &'static str {
        "installed"
    }
}

#[async_trait::async_trait(?Send)]
impl StateChangeImpl for Install {
    fn name(&self) -> &'static str {
        "install"
    }

    async fn handle(mut self, context: &mut Context) -> Result<(State, machine::StepTransition)> {
        let package_uid = self.update_package.package_uid();
        info!("installing update: {}", &package_uid);

        let installation_set = context.runtime_settings.get_inactive_installation_set()?;
        info!("using installation set as target {}", installation_set);

        let objs = self.update_package.objects_mut(installation_set);
        objs.iter().try_for_each(object::Installer::check_requirements)?;
        objs.iter_mut().try_for_each(|obj| obj.install(&context.settings.update.download_dir))?;

        // Avoid installing same package twice.
        context.runtime_settings.set_applied_package_uid(&package_uid)?;

        // Set upgrading to the new installation set
        context.runtime_settings.set_upgrading_to(installation_set)?;

        // Swap installation set so it is used next device boot.
        installation_set::swap_active()?;
        info!("swapping active installation set");

        info!("update installed successfully");
        Ok((
            State::Reboot(Reboot { update_package: self.update_package }),
            machine::StepTransition::Immediate,
        ))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::update_package::tests::get_update_package;
    use pretty_assertions::assert_eq;

    #[async_std::test]
    async fn has_package_uid_if_succeed() {
        let setup = crate::tests::TestEnvironment::build().finish();
        let mut context = setup.gen_context();
        let state = Install { update_package: get_update_package() };

        let machine = State::Install(state).move_to_next_state(&mut context).await.unwrap().0;

        match machine {
            State::Reboot(_) => assert_eq!(
                context.runtime_settings.applied_package_uid(),
                Some(get_update_package().package_uid())
            ),
            s => panic!("Invalid success: {:?}", s),
        }
    }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use csv;
use curl::http;
use regex::Regex;
use rustc_serialize::json;
use std::collections::HashMap;
use std::fs::File;
use std::process;
use std::result::Result;
use std::str;

use say;
use format::{OutputFormat};
use github::entities::{Issue, Issues, GithubError};

fn ratelimit(headers: &HashMap<String, Vec<String>>) -> u32 {
    let rate = headers.get("x-ratelimit-remaining").unwrap()
                      .first().unwrap();

    rate.parse().unwrap()
}
#[test]
fn valid_ratelimit() {
    let mut headers: HashMap<String, Vec<String>> = HashMap::new();
    headers.insert("x-ratelimit-remaining".to_owned(), vec!["1".to_owned()]);

    assert_eq!(ratelimit(&headers), 1);
}

fn get_page(url: String, token: &str) -> http::Response {
    println!("{} {} {}", say::info(), "Fetching", url);

    let auth_header = format!("token {}", token);
    let res = http::handle()
                   .get(url)
                   .header("Authorization", &auth_header)
                   .header("User-Agent", "Github-Issues-CLI")
                   .header("Accept", "application/vnd.github.v3+json")
                   .exec()
                   .unwrap_or_else(|e| process::exit(1));

    if res.get_code() != 200 {
        match str::from_utf8(res.get_body()) {
            Ok(b) => {
                println!("{} {:?}", say::error(), json::decode::<GithubError>(b).ok());
                process::exit(1)
            }
            Err(..) => {
                println!("{} {}", say::error(), "Unable to parse the response from Github");
                process::exit(1)
            }
        }
    }

    res
}

fn next_url(link: String) -> Option<String> {
    let re = Regex::new(r"<([^;]+)>;\s*rel=.next.").unwrap();
    match re.captures(&link) {
        None => None,
        Some(cs) => cs.at(1).as_ref().map(|x| x.to_string())
    }
}

fn as_issues(raw: &[u8]) -> Result<Issues, json::DecoderError> {
    match str::from_utf8(raw) {
        Ok(b) => json::decode(b),
        Err(..) => {
            println!("{} {}", say::error(), "Unable to parse the response from Github");
            process::exit(1)
        }
    }
}

fn parse_repopath(path: String) -> (String, String) {
    let list: Vec<&str> = path.split("/").collect();

    (list[0].to_string(), list[1].to_string())
}

pub fn run(repopath: String,
           oauth_token: String,
           labels: Vec<String>,
           state: String,
           format: OutputFormat,
           output_file: String) {

    // let (owner, repo) = parse_repopath(repopath);
    let labels_pair = if labels.is_empty() { "".to_owned() }
                      else { format!("&labels={}", labels.join(",")) };
    let url = format!("https://api.github.com/repos/{}/issues?filter=all&state={}{}",
                      repopath, state, labels_pair);

    let res = get_page(url, &oauth_token);
    let mut issues = as_issues(res.get_body()).unwrap();

    // A Link header is not present if the requested collection has less than
    // _pagesize_.
    match res.get_headers().get("link") {
        Some(links) => {
            let mut nurl = next_url(links.first().unwrap().clone());

            while let Some(nu) = nurl {
                let r = get_page(nu.to_string(), &oauth_token);
                issues.extend(as_issues(r.get_body()).unwrap());

                let link = r.get_headers().get("link").unwrap()
                                          .first().unwrap()
                                          .clone();
                nurl = next_url(link);
                if nurl.is_none() {
                    println!("{} {} {}", say::warn(), ratelimit(r.get_headers()), "Remaining requests");
                }
            }
        }
        _ => {
            println!("{} {} {}", say::warn(), ratelimit(res.get_headers()), "Remaining requests");
        }
    }

    println!("{} {}", say::highlight("Total issues collected:"), issues.len());

    match format {
        OutputFormat::CSV => write_csv(issues, output_file),
        OutputFormat::JSON => write_json(issues, output_file),
    }
}

fn write_json(issues: Issues, output_file: String) {
    let mut f = File::create(output_file).unwrap();
    let string: String = json::encode(&issues).unwrap();
    f.write_all(string.as_bytes());
}

fn write_csv(issues: Issues, output_file: String) {
    let mut wtr = csv::Writer::from_file(output_file).unwrap();

    let headers = ("number",
                   "title",
                   "state",
                   "created_at",
                   "closed_at",
                   "assignee",
                   "user",
                   "labels",
                   "body");
    wtr.encode(headers);

    for issue in issues {
        let labels = issue.labels.iter()
                                 .map(|x| x.name.clone())
                                 .collect::<Vec<String>>()
                                 .join(",");
        let user = issue.user;
        let assignee = issue.assignee;

        let row = (issue.number,
                   issue.title,
                   issue.state,
                   issue.created_at,
                   issue.closed_at,
                   assignee,
                   user,
                   labels,
                   issue.body);

        wtr.encode(row);
    }
}
<commit_msg>Remove unused warnings<commit_after>use std::io::prelude::*;
use csv;
use curl::http;
use regex::Regex;
use rustc_serialize::json;
use std::collections::HashMap;
use std::fs::File;
use std::process;
use std::result::Result;
use std::str;

use say;
use format::{OutputFormat};
use github::entities::{Issues, GithubError};

fn ratelimit(headers: &HashMap<String, Vec<String>>) -> u32 {
    let rate = headers.get("x-ratelimit-remaining").unwrap()
                      .first().unwrap();

    rate.parse().unwrap()
}
#[test]
fn valid_ratelimit() {
    let mut headers: HashMap<String, Vec<String>> = HashMap::new();
    headers.insert("x-ratelimit-remaining".to_owned(), vec!["1".to_owned()]);

    assert_eq!(ratelimit(&headers), 1);
}

fn get_page(url: String, token: &str) -> http::Response {
    println!("{} {} {}", say::info(), "Fetching", url);

    let auth_header = format!("token {}", token);
    let res = http::handle()
                   .get(url)
                   .header("Authorization", &auth_header)
                   .header("User-Agent", "Github-Issues-CLI")
                   .header("Accept", "application/vnd.github.v3+json")
                   .exec()
                   .unwrap_or_else(|_| process::exit(1));

    if res.get_code() != 200 {
        match str::from_utf8(res.get_body()) {
            Ok(b) => {
                println!("{} {:?}", say::error(), json::decode::<GithubError>(b).ok());
                process::exit(1)
            }
            Err(..) => {
                println!("{} {}", say::error(), "Unable to parse the response from Github");
                process::exit(1)
            }
        }
    }

    res
}

fn next_url(link: String) -> Option<String> {
    let re = Regex::new(r"<([^;]+)>;\s*rel=.next.").unwrap();
    match re.captures(&link) {
        None => None,
        Some(cs) => cs.at(1).as_ref().map(|x| x.to_string())
    }
}

fn as_issues(raw: &[u8]) -> Result<Issues, json::DecoderError> {
    match str::from_utf8(raw) {
        Ok(b) => json::decode(b),
        Err(..) => {
            println!("{} {}", say::error(), "Unable to parse the response from Github");
            process::exit(1)
        }
    }
}

// TODO: Review its need
// fn parse_repopath(path: String) -> (String, String) {
//     let list: Vec<&str> = path.split("/").collect();

//     (list[0].to_string(), list[1].to_string())
// }

pub fn run(repopath: String,
           oauth_token: String,
           labels: Vec<String>,
           state: String,
           format: OutputFormat,
           output_file: String) {

    // let (owner, repo) = parse_repopath(repopath);
    let labels_pair = if labels.is_empty() { "".to_owned() }
                      else { format!("&labels={}", labels.join(",")) };
    let url = format!("https://api.github.com/repos/{}/issues?filter=all&state={}{}",
                      repopath, state, labels_pair);

    let res = get_page(url, &oauth_token);
    let mut issues = as_issues(res.get_body()).unwrap();

    // A Link header is not present if the requested collection has less than
    // _pagesize_.
    match res.get_headers().get("link") {
        Some(links) => {
            let mut nurl = next_url(links.first().unwrap().clone());

            while let Some(nu) = nurl {
                let r = get_page(nu.to_string(), &oauth_token);
                issues.extend(as_issues(r.get_body()).unwrap());

                let link = r.get_headers().get("link").unwrap()
                                          .first().unwrap()
                                          .clone();
                nurl = next_url(link);
                if nurl.is_none() {
                    println!("{} {} {}", say::warn(), ratelimit(r.get_headers()), "Remaining requests");
                }
            }
        }
        _ => {
            println!("{} {} {}", say::warn(), ratelimit(res.get_headers()), "Remaining requests");
        }
    }

    println!("{} {}", say::highlight("Total issues collected:"), issues.len());

    match format {
        OutputFormat::CSV => write_csv(issues, output_file),
        OutputFormat::JSON => write_json(issues, output_file),
    }
}

fn write_json(issues: Issues, output_file: String) {
    let mut f = File::create(output_file).unwrap();
    let string: String = json::encode(&issues).unwrap();
    let _ = f.write_all(string.as_bytes());
}

fn write_csv(issues: Issues, output_file: String) {
    let mut wtr = csv::Writer::from_file(output_file).unwrap();

    let headers = ("number",
                   "title",
                   "state",
                   "created_at",
                   "closed_at",
                   "assignee",
                   "user",
                   "labels",
                   "body");
    let _ = wtr.encode(headers);

    for issue in issues {
        let labels = issue.labels.iter()
                                 .map(|x| x.name.clone())
                                 .collect::<Vec<String>>()
                                 .join(",");
        let user = issue.user;
        let assignee = issue.assignee;

        let row = (issue.number,
                   issue.title,
                   issue.state,
                   issue.created_at,
                   issue.closed_at,
                   assignee,
                   user,
                   labels,
                   issue.body);

        let _ = wtr.encode(row);
    }
}
<|endoftext|>


<commit_before>use crate::convert::*;
use core::hash::{Hasher};

///Just a simple bit pattern.
const PAD : u128 = 0xF0E1_D2C3_B4A5_9687_7869_5A4B_3C2D_1E0F;

/// A `Hasher` for hashing an arbitrary stream of bytes.
///
/// Instances of [AHasher] represent state that is updated while hashing data.
///
/// Each method updates the internal state based on the new data provided. Once
/// all of the data has been provided, the resulting hash can be obtained by calling
/// `finish()`
///
/// [Clone] is also provided in case you wish to calculate hashes for two different items that
/// start with the same data.
///
#[derive(Debug, Clone)]
pub struct AHasher {
    buffer: [u64; 2],
}

impl AHasher {
    /// Creates a new hasher keyed to the provided keys.
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    /// use ahash::AHasher;
    ///
    /// let mut hasher = AHasher::new_with_keys(123, 456);
    ///
    /// hasher.write_u32(1989);
    /// hasher.write_u8(11);
    /// hasher.write_u8(9);
    /// hasher.write(b"Huh?");
    ///
    /// println!("Hash is {:x}!", hasher.finish());
    /// ```
    #[inline]
    pub(crate) fn new_with_keys(key0: u64, key1: u64) -> AHasher {
        AHasher { buffer: [key0, key1] }
    }

    #[inline]
    pub(crate) fn new_with_key(key: [u64; 2], loc: usize) -> AHasher {
        AHasher { buffer: [key[0], key[1] ^ (loc as u64)] }
    }
}

#[inline(never)]
#[no_mangle]
fn hash_test_aes(input: &[u8]) -> u64 {
    let mut a = AHasher::new_with_keys(67, 87);
    a.write(input);
    a.finish()
}

/// Provides methods to hash all of the primitive types.
impl Hasher for AHasher {
    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u128(&mut self, i: u128) {
        self.buffer = aeshash(self.buffer.convert(),i).convert();
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.write_u64(i as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write(&mut self, input: &[u8]) {
        let mut data = input;
        let length = data.len() as u64;
        //This will be scrambled by the first AES round in any branch.
        self.buffer[1] ^= length;
        //A 'binary search' on sizes reduces the number of comparisons.
        if data.len() > 8 {
            if data.len() > 32 {
                if data.len() > 64 {
                    let (_, tail) = data.split_at(data.len() - 32);
                    let mut par_block: u128 = self.buffer.convert();
                    while data.len() > 64 {
                        let (b1, rest) = data.read_u128();
                        par_block = aeshash(par_block, b1);
                        data = rest;
                        let (b2, rest) = data.read_u128();
                        self.buffer = aeshash(self.buffer.convert(), b2).convert();
                        data = rest;
                    }
                    let (b1, rest) = tail.read_u128();
                    par_block = aeshash(par_block, b1);
                    let (b2, _) = rest.read_u128();
                    self.buffer = aeshash(self.buffer.convert(), b2).convert();
                    self.buffer = aeshash(self.buffer.convert(), par_block).convert();
                } else {
                    //len 33-64
                    let last = data.read_last_u128();
                    while data.len() > 16 {
                        let (block, rest) = data.read_u128();
                        self.buffer = aeshash(self.buffer.convert(), block).convert();
                        data = rest;
                    }
                    self.buffer = aeshash(self.buffer.convert(), last).convert();
                }
            } else {
                if data.len() > 16 {
                    //len 17-32
                    self.buffer = aeshash(self.buffer.convert(), data.read_u128().0).convert();
                    self.buffer = aeshash(self.buffer.convert(), data.read_last_u128()).convert();
                } else {
                    //len 9-16
                    self.buffer = aeshash(self.buffer.convert(), data.read_u64().0 as u128).convert();
                    self.buffer = aeshash(self.buffer.convert(), data.read_last_u64() as u128).convert();
                }
            }
        } else {
            if data.len() >= 2 {
                if data.len() >= 4 {
                    //len 4-8
                    self.buffer = aeshash(self.buffer.convert(),data.read_u32().0 as u128).convert();
                    self.buffer = aeshash(self.buffer.convert(),data.read_last_u32() as u128).convert();
                } else {
                    //len 2-3
                    self.buffer = aeshash(self.buffer.convert(),data.read_u16().0 as u128).convert();
                    self.buffer = aeshash(self.buffer.convert(),data[data.len()-1] as u128).convert();
                }
            } else {
                let value;
                if data.len() > 0 {
                    value = data[0]; //len 1
                } else {
                    value = 0;
                }
                self.buffer = aeshash(self.buffer.convert(), value as u128).convert();
            }
        }
    }
    #[inline]
    fn finish(&self) -> u64 {
        let result: [u64; 2] = aeshash(aeshash(self.buffer.convert(), PAD), PAD).convert();
        result[0]//.wrapping_add(result[1])
    }
}

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
#[inline(always)]
fn aeshash(value: u128, xor: u128) -> u128 {
    use core::mem::transmute;
    #[cfg(target_arch = "x86")]
    use core::arch::x86::*;
    #[cfg(target_arch = "x86_64")]
    use core::arch::x86_64::*;
    unsafe {
        let value = transmute(value);
        transmute(_mm_aesdec_si128(value, transmute(xor)))
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::hash::{BuildHasherDefault};
    use crate::convert::Convert;
    use crate::aes_hash::*;

    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
        map.insert(1, 3);
    }

    #[test]
    fn test_default() {
        let hasher_a = AHasher::default();
        assert_ne!(0, hasher_a.buffer[0]);
        assert_ne!(0, hasher_a.buffer[1]);
        assert_ne!(hasher_a.buffer[0], hasher_a.buffer[1]);
        let hasher_b = AHasher::default();
        assert_eq!(hasher_a.buffer[0], hasher_b.buffer[0]);
        assert_eq!(hasher_a.buffer[1], hasher_b.buffer[1]);
    }

    #[test]
    fn test_hash() {
        let mut result: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value: [u64; 2] = [1 << 32, 0xFEDCBA9876543210];
        result = aeshash(value.convert(), result.convert()).convert();
        result = aeshash(result.convert(), result.convert()).convert();
        let mut result2: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value2: [u64; 2] = [1, 0xFEDCBA9876543210];
        result2 = aeshash(value2.convert(), result2.convert()).convert();
        result2 = aeshash(result2.convert(), result.convert()).convert();
        let result: [u8; 16] = result.convert();
        let result2: [u8; 16] = result2.convert();
        assert_ne!(hex::encode(result), hex::encode(result2));
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}
<commit_msg>Remove loop for 33-64 bytes<commit_after>use crate::convert::*;
use core::hash::{Hasher};

///Just a simple bit pattern.
const PAD : u128 = 0xF0E1_D2C3_B4A5_9687_7869_5A4B_3C2D_1E0F;

/// A `Hasher` for hashing an arbitrary stream of bytes.
///
/// Instances of [AHasher] represent state that is updated while hashing data.
///
/// Each method updates the internal state based on the new data provided. Once
/// all of the data has been provided, the resulting hash can be obtained by calling
/// `finish()`
///
/// [Clone] is also provided in case you wish to calculate hashes for two different items that
/// start with the same data.
///
#[derive(Debug, Clone)]
pub struct AHasher {
    buffer: [u64; 2],
}

impl AHasher {
    /// Creates a new hasher keyed to the provided keys.
    /// # Example
    ///
    /// ```
    /// use std::hash::Hasher;
    /// use ahash::AHasher;
    ///
    /// let mut hasher = AHasher::new_with_keys(123, 456);
    ///
    /// hasher.write_u32(1989);
    /// hasher.write_u8(11);
    /// hasher.write_u8(9);
    /// hasher.write(b"Huh?");
    ///
    /// println!("Hash is {:x}!", hasher.finish());
    /// ```
    #[inline]
    pub(crate) fn new_with_keys(key0: u64, key1: u64) -> AHasher {
        AHasher { buffer: [key0, key1] }
    }

    #[inline]
    pub(crate) fn new_with_key(key: [u64; 2], loc: usize) -> AHasher {
        AHasher { buffer: [key[0], key[1] ^ (loc as u64)] }
    }
}

#[inline(never)]
#[no_mangle]
fn hash_test_aes(input: &[u8]) -> u64 {
    let mut a = AHasher::new_with_keys(67, 87);
    a.write(input);
    a.finish()
}

/// Provides methods to hash all of the primitive types.
impl Hasher for AHasher {
    #[inline]
    fn write_u8(&mut self, i: u8) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write_u128(&mut self, i: u128) {
        self.buffer = aeshash(self.buffer.convert(),i).convert();
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.write_u64(i as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.write_u128(i as u128);
    }

    #[inline]
    fn write(&mut self, input: &[u8]) {
        let mut data = input;
        let length = data.len() as u64;
        //This will be scrambled by the first AES round in any branch.
        self.buffer[1] ^= length;
        //A 'binary search' on sizes reduces the number of comparisons.
        if data.len() > 8 {
            if data.len() > 32 {
                if data.len() > 64 {
                    let (_, tail) = data.split_at(data.len() - 32);
                    let mut par_block: u128 = self.buffer.convert();
                    while data.len() > 64 {
                        let (b1, rest) = data.read_u128();
                        par_block = aeshash(par_block, b1);
                        data = rest;
                        let (b2, rest) = data.read_u128();
                        self.buffer = aeshash(self.buffer.convert(), b2).convert();
                        data = rest;
                    }
                    let (b1, rest) = tail.read_u128();
                    par_block = aeshash(par_block, b1);
                    let (b2, _) = rest.read_u128();
                    self.buffer = aeshash(self.buffer.convert(), b2).convert();
                    self.buffer = aeshash(self.buffer.convert(), par_block).convert();
                } else {
                    //len 33-64
                    let (head, _) = data.split_at(32);
                    let (_, tail) = data.split_at(data.len() - 32);
                    self.buffer = aeshash(self.buffer.convert(), head.read_u128().0).convert();
                    self.buffer = aeshash(self.buffer.convert(), head.read_last_u128()).convert();
                    self.buffer = aeshash(self.buffer.convert(), tail.read_u128().0).convert();
                    self.buffer = aeshash(self.buffer.convert(), tail.read_last_u128()).convert();
                }
            } else {
                if data.len() > 16 {
                    //len 17-32
                    self.buffer = aeshash(self.buffer.convert(), data.read_u128().0).convert();
                    self.buffer = aeshash(self.buffer.convert(), data.read_last_u128()).convert();
                } else {
                    //len 9-16
                    self.buffer = aeshash(self.buffer.convert(), data.read_u64().0 as u128).convert();
                    self.buffer = aeshash(self.buffer.convert(), data.read_last_u64() as u128).convert();
                }
            }
        } else {
            if data.len() >= 2 {
                if data.len() >= 4 {
                    //len 4-8
                    self.buffer = aeshash(self.buffer.convert(),data.read_u32().0 as u128).convert();
                    self.buffer = aeshash(self.buffer.convert(),data.read_last_u32() as u128).convert();
                } else {
                    //len 2-3
                    self.buffer = aeshash(self.buffer.convert(),data.read_u16().0 as u128).convert();
                    self.buffer = aeshash(self.buffer.convert(),data[data.len()-1] as u128).convert();
                }
            } else {
                let value;
                if data.len() > 0 {
                    value = data[0]; //len 1
                } else {
                    value = 0;
                }
                self.buffer = aeshash(self.buffer.convert(), value as u128).convert();
            }
        }
    }
    #[inline]
    fn finish(&self) -> u64 {
        let result: [u64; 2] = aeshash(aeshash(self.buffer.convert(), PAD), PAD).convert();
        result[0]//.wrapping_add(result[1])
    }
}

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes"))]
#[inline(always)]
fn aeshash(value: u128, xor: u128) -> u128 {
    use core::mem::transmute;
    #[cfg(target_arch = "x86")]
    use core::arch::x86::*;
    #[cfg(target_arch = "x86_64")]
    use core::arch::x86_64::*;
    unsafe {
        let value = transmute(value);
        transmute(_mm_aesdec_si128(value, transmute(xor)))
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::hash::{BuildHasherDefault};
    use crate::convert::Convert;
    use crate::aes_hash::*;

    #[test]
    fn test_builder() {
        let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default();
        map.insert(1, 3);
    }

    #[test]
    fn test_default() {
        let hasher_a = AHasher::default();
        assert_ne!(0, hasher_a.buffer[0]);
        assert_ne!(0, hasher_a.buffer[1]);
        assert_ne!(hasher_a.buffer[0], hasher_a.buffer[1]);
        let hasher_b = AHasher::default();
        assert_eq!(hasher_a.buffer[0], hasher_b.buffer[0]);
        assert_eq!(hasher_a.buffer[1], hasher_b.buffer[1]);
    }

    #[test]
    fn test_hash() {
        let mut result: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value: [u64; 2] = [1 << 32, 0xFEDCBA9876543210];
        result = aeshash(value.convert(), result.convert()).convert();
        result = aeshash(result.convert(), result.convert()).convert();
        let mut result2: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
        let value2: [u64; 2] = [1, 0xFEDCBA9876543210];
        result2 = aeshash(value2.convert(), result2.convert()).convert();
        result2 = aeshash(result2.convert(), result.convert()).convert();
        let result: [u8; 16] = result.convert();
        let result2: [u8; 16] = result2.convert();
        assert_ne!(hex::encode(result), hex::encode(result2));
    }

    #[test]
    fn test_conversion() {
        let input: &[u8] = "dddddddd".as_bytes();
        let bytes: u64 = as_array!(input, 8).convert();
        assert_eq!(bytes, 0x6464646464646464);
    }
}
<|endoftext|>


<commit_before>use frontend::scanner::{scan_into_iterator, Position, ScannerError, Token, TokenWithContext};
use std::iter::Peekable;
use vm::bytecode::{BinaryOp, Chunk, OpCode};

enum ParsingError {
    UnexpectedEndOfFile,
    Unexpected(String, Position),
}

enum CompilationError {
    ScannerError(ScannerError),
    ParsingError(ParsingError),
}

#[derive(PartialEq, PartialOrd)]
enum Precedence {
    None,
    Assignment,
    Or,
    And,
    Equality,
    Comparison,
    Term,
    Factor,
    Unary,
    Call,
    Primary,
}

impl Precedence {
    fn next(&self) -> Precedence {
        match *self {
            Precedence::None => Precedence::Assignment,
            Precedence::Assignment => Precedence::Or,
            Precedence::Or => Precedence::And,
            Precedence::And => Precedence::Equality,
            Precedence::Equality => Precedence::Comparison,
            Precedence::Comparison => Precedence::Term,
            Precedence::Term => Precedence::Factor,
            Precedence::Factor => Precedence::Unary,
            Precedence::Unary => Precedence::Call,
            Precedence::Call => Precedence::Primary,
            Precedence::Primary => panic!("What is it supposed to happen"),
        }
    }
}

//TODO: replace with "function pointers", if possible
enum RuleFunction {
    Grouping,
    Unary,
    Binary,
    Number,
}

struct Rule {
    precedence: Precedence,
    prefix: Option<RuleFunction>,
    infix: Option<RuleFunction>,
}

impl Rule {
    /// Finds the rule associated with a Token type.
    /// This is derived straight from the Pratt Parser table.
    fn find(token: &Token) -> Rule {
        match token {
            Token::LeftParen => Rule {
                precedence: Precedence::Call,
                prefix: Some(RuleFunction::Grouping),
                infix: None,
            },
            Token::RightParen => Rule {
                precedence: Precedence::None,
                prefix: None,
                infix: None,
            },
            Token::LeftBrace => Rule {
                precedence: Precedence::None,
                prefix: Some(RuleFunction::Grouping),
                infix: None,
            },
            Token::RightBrace => Rule {
                precedence: Precedence::None,
                prefix: None,
                infix: None,
            },
            Token::Comma => Rule {
                precedence: Precedence::None,
                prefix: None,
                infix: None,
            },
            Token::Dot => Rule {
                precedence: Precedence::Call,
                prefix: None,
                infix: None,
            },
            Token::Minus => Rule {
                precedence: Precedence::Term,
                prefix: Some(RuleFunction::Unary),
                infix: Some(RuleFunction::Binary),
            },
            Token::Plus => Rule {
                precedence: Precedence::Term,
                prefix: None,
                infix: Some(RuleFunction::Binary),
            },
            Token::Slash => Rule {
                precedence: Precedence::Factor,
                prefix: None,
                infix: Some(RuleFunction::Binary),
            },
            Token::Star => Rule {
                precedence: Precedence::Factor,
                prefix: None,
                infix: Some(RuleFunction::Binary),
            },
            Token::Semicolon => Rule {
                precedence: Precedence::None,
                prefix: None,
                infix: None,
            },
            Token::NumberLiteral(_) => Rule {
                precedence: Precedence::None,
                prefix: Some(RuleFunction::Number),
                infix: None,
            },
            _ => unimplemented!(),
            /*
  { NULL,     NULL,    PREC_NONE },       // TOKEN_BANG
  { NULL,     NULL,    PREC_EQUALITY },   // TOKEN_BANG_EQUAL
  { NULL,     NULL,    PREC_NONE },       // TOKEN_EQUAL
  { NULL,     NULL,    PREC_EQUALITY },   // TOKEN_EQUAL_EQUAL
  { NULL,     NULL,    PREC_COMPARISON }, // TOKEN_GREATER
  { NULL,     NULL,    PREC_COMPARISON }, // TOKEN_GREATER_EQUAL
  { NULL,     NULL,    PREC_COMPARISON }, // TOKEN_LESS
  { NULL,     NULL,    PREC_COMPARISON }, // TOKEN_LESS_EQUAL
  { NULL,     NULL,    PREC_NONE },       // TOKEN_IDENTIFIER
  { NULL,     NULL,    PREC_NONE },       // TOKEN_STRING
  { NULL,     NULL,    PREC_AND },        // TOKEN_AND
  { NULL,     NULL,    PREC_NONE },       // TOKEN_CLASS
  { NULL,     NULL,    PREC_NONE },       // TOKEN_ELSE
  { NULL,     NULL,    PREC_NONE },       // TOKEN_FALSE
  { NULL,     NULL,    PREC_NONE },       // TOKEN_FUN
  { NULL,     NULL,    PREC_NONE },       // TOKEN_FOR
  { NULL,     NULL,    PREC_NONE },       // TOKEN_IF
  { NULL,     NULL,    PREC_NONE },       // TOKEN_NIL
  { NULL,     NULL,    PREC_OR },         // TOKEN_OR
  { NULL,     NULL,    PREC_NONE },       // TOKEN_PRINT
  { NULL,     NULL,    PREC_NONE },       // TOKEN_RETURN
  { NULL,     NULL,    PREC_NONE },       // TOKEN_SUPER
  { NULL,     NULL,    PREC_NONE },       // TOKEN_THIS
  { NULL,     NULL,    PREC_NONE },       // TOKEN_TRUE
  { NULL,     NULL,    PREC_NONE },       // TOKEN_VAR
  { NULL,     NULL,    PREC_NONE },       // TOKEN_WHILE
  { NULL,     NULL,    PREC_NONE },       // TOKEN_ERROR
  { NULL,     NULL,    PREC_NONE },       // TOKEN_EOF
*/
        }
    }
}

struct Parser<'a, I>
where
    I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
{
    chunk: &'a mut Chunk,
    tokens: Peekable<I>,
    errors: Vec<CompilationError>,
}

impl<'a, I> Parser<'a, I>
where
    I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
{
    fn new(chunk: &'a mut Chunk, tokens: I) -> Parser<I> {
        Parser {
            chunk: chunk,
            tokens: tokens.peekable(),
            errors: vec![],
        }
    }

    fn skip_to_valid(&mut self) -> () {
        loop {
            match self.tokens.peek() {
                Some(Ok(TokenWithContext {
                    token: Token::Whitespace,
                    lexeme: _,
                    position: _,
                })) => {
                    // No op, just skip it
                }
                Some(Ok(TokenWithContext {
                    token: Token::Comment,
                    lexeme: _,
                    position: _,
                })) => {
                    // No op, just skip it
                }
                Some(Err(ref e)) => {
                    self.errors.push(CompilationError::ScannerError(e.clone()));
                }
                _ => return (),
            }
            let _ = self.tokens.next();
        }
    }

    /// Advances to the next valid token (skipping and keeping track of errors).
    /// This consumes an item from the token stream and returns it.
    fn advance(&mut self) -> Option<TokenWithContext> {
        // Peek to skip errors and keep track of them.
        // This makes unwrapping safe.
        self.skip_to_valid();
        self.tokens.next().map(|r| r.unwrap())
    }

    /// Adds an opcode to the current chunk
    fn emit(&mut self, opcode: OpCode, line: usize) -> () {
        self.chunk.add_instruction(opcode, line)
    }

    fn peek(&mut self) -> Option<&TokenWithContext> {
        self.skip_to_valid();
        self.tokens.peek().map(|result| match result {
            Ok(ref token_with_context) => token_with_context,
            Err(_) => unreachable!("We already skipped errors"),
        })
    }

    fn dispatch(&mut self, rule_function: RuleFunction) -> Result<(), ParsingError> {
        match rule_function {
            RuleFunction::Grouping => self.grouping(),
            RuleFunction::Unary => self.unary(),
            RuleFunction::Binary => self.binary(),
            RuleFunction::Number => self.number(),
        }
    }

    fn parse_precedence(&mut self, precedence: Precedence) -> Result<(), ParsingError> {
        let prefix_function = {
            let peeked = self.peek().ok_or(ParsingError::UnexpectedEndOfFile)?;
            Rule::find(&peeked.token)
                .prefix
                .ok_or_else(|| ParsingError::Unexpected(peeked.lexeme.clone(), peeked.position))?
        };
        self.dispatch(prefix_function)?;
        loop {
            let infix_function = {
                match self.peek() {
                    Some(peeked) => {
                        let infix_rule = Rule::find(&peeked.token);
                        if precedence <= infix_rule.precedence {
                            infix_rule.infix.ok_or_else(|| {
                                ParsingError::Unexpected(peeked.lexeme.clone(), peeked.position)
                            })?
                        } else {
                            return Ok(());
                        }
                    }
                    None => return Ok(()),
                }
            };
            self.dispatch(infix_function)?;
        }
    }

    fn expression(&mut self) -> Result<(), ParsingError> {
        self.parse_precedence(Precedence::Assignment)
    }

    fn consume(&mut self, token: Token) -> Result<(), ParsingError> {
        let current = self.advance().ok_or(ParsingError::UnexpectedEndOfFile)?;
        if current.token == token {
            Ok(())
        } else {
            Err(ParsingError::Unexpected(
                current.lexeme.clone(),
                current.position,
            ))
        }
    }

    fn number(&mut self) -> Result<(), ParsingError> {
        let current = self.advance();
        let (value, line) = if let Some(ref t) = current {
            if let Token::NumberLiteral(ref n) = t.token {
                (*n, t.position.line)
            } else {
                unreachable!()
            }
        } else {
            panic!()
        };
        let constant = self.chunk.add_constant(value);
        self.chunk.add_instruction(OpCode::Constant(constant), line);
        Ok(())
    }

    fn grouping(&mut self) -> Result<(), ParsingError> {
        let _ = self.consume(Token::LeftParen)?;
        self.expression()?;
        self.consume(Token::RightParen)
    }

    fn unary(&mut self) -> Result<(), ParsingError> {
        let (opcode, line) = match self.advance() {
            Some(TokenWithContext {
                token: Token::Minus,
                position,
                lexeme: _,
            }) => (OpCode::Negate, position.line),
            _ => unreachable!("This code is executed only when we know we have a unary expression"),
        };
        let _ = self.parse_precedence(Precedence::Unary)?;
        self.emit(opcode, line);
        Ok(())
    }

    fn binary(&mut self) -> Result<(), ParsingError> {
        let (opcode, line) = match self.advance() {
            Some(TokenWithContext {
                token: Token::Plus,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Add), position.line),
            Some(TokenWithContext {
                token: Token::Minus,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Subtract), position.line),
            Some(TokenWithContext {
                token: Token::Star,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Multiply), position.line),
            Some(TokenWithContext {
                token: Token::Slash,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Divide), position.line),
            _ => {
                unreachable!("This code is executed only when we know we have a binary expression")
            }
        };
        let precedence = {
            let peeked = self
                .peek()
                .ok_or_else(|| ParsingError::UnexpectedEndOfFile)?;
            Rule::find(&peeked.token).precedence.next()
        };
        self.parse_precedence(precedence)?;
        self.emit(opcode, line);
        Ok(())
    }

    fn parse(&mut self) -> Result<(), ()> {
        loop {
            match self.expression() {
                Ok(()) => return Ok(()),
                Err(error) => {
                    self.errors.push(CompilationError::ParsingError(error))
                    //TODO: add recovery mode
                }
            }
        }
    }
}

pub fn compile(text: &str) -> Result<Chunk, ()> {
    let mut chunk = Chunk::new();
    let tokens = scan_into_iterator(text);
    {
        let mut parser = Parser::new(&mut chunk, tokens);
        parser.parse()?;
        // TODO: assert that we consumed everything
        parser.emit(OpCode::Return, 0); // Line is meaningless
    }
    Ok(chunk)
}
<commit_msg>Use function pointers<commit_after>use frontend::scanner::{scan_into_iterator, Position, ScannerError, Token, TokenWithContext};
use std::iter::Peekable;
use vm::bytecode::{BinaryOp, Chunk, OpCode};

enum ParsingError {
    UnexpectedEndOfFile,
    Unexpected(String, Position),
}

enum CompilationError {
    ScannerError(ScannerError),
    ParsingError(ParsingError),
}

#[derive(PartialEq, PartialOrd)]
enum Precedence {
    None,
    Assignment,
    Or,
    And,
    Equality,
    Comparison,
    Term,
    Factor,
    Unary,
    Call,
    Primary,
}

impl Precedence {
    fn next(&self) -> Precedence {
        match *self {
            Precedence::None => Precedence::Assignment,
            Precedence::Assignment => Precedence::Or,
            Precedence::Or => Precedence::And,
            Precedence::And => Precedence::Equality,
            Precedence::Equality => Precedence::Comparison,
            Precedence::Comparison => Precedence::Term,
            Precedence::Term => Precedence::Factor,
            Precedence::Factor => Precedence::Unary,
            Precedence::Unary => Precedence::Call,
            Precedence::Call => Precedence::Primary,
            Precedence::Primary => panic!("What is it supposed to happen"),
        }
    }
}

struct Parser<'a, I>
where
    I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
{
    chunk: &'a mut Chunk,
    tokens: Peekable<I>,
    errors: Vec<CompilationError>,
}

impl<'a, I> Parser<'a, I>
where
    I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
{
    fn new(chunk: &'a mut Chunk, tokens: I) -> Parser<I> {
        Parser {
            chunk: chunk,
            tokens: tokens.peekable(),
            errors: vec![],
        }
    }

    fn skip_to_valid(&mut self) -> () {
        loop {
            match self.tokens.peek() {
                Some(Ok(TokenWithContext {
                    token: Token::Whitespace,
                    lexeme: _,
                    position: _,
                })) => {
                    // No op, just skip it
                }
                Some(Ok(TokenWithContext {
                    token: Token::Comment,
                    lexeme: _,
                    position: _,
                })) => {
                    // No op, just skip it
                }
                Some(Err(ref e)) => {
                    self.errors.push(CompilationError::ScannerError(e.clone()));
                }
                _ => return (),
            }
            let _ = self.tokens.next();
        }
    }

    /// Advances to the next valid token (skipping and keeping track of errors).
    /// This consumes an item from the token stream and returns it.
    fn advance(&mut self) -> Option<TokenWithContext> {
        // Peek to skip errors and keep track of them.
        // This makes unwrapping safe.
        self.skip_to_valid();
        self.tokens.next().map(|r| r.unwrap())
    }

    /// Adds an opcode to the current chunk
    fn emit(&mut self, opcode: OpCode, line: usize) -> () {
        self.chunk.add_instruction(opcode, line)
    }

    fn peek(&mut self) -> Option<&TokenWithContext> {
        self.skip_to_valid();
        self.tokens.peek().map(|result| match result {
            Ok(ref token_with_context) => token_with_context,
            Err(_) => unreachable!("We already skipped errors"),
        })
    }

    fn find_rule(
        token: &Token,
    ) -> (
        Precedence,
        Option<fn(&mut Self) -> Result<(), ParsingError>>,
        Option<fn(&mut Self) -> Result<(), ParsingError>>,
    )
    where
        I: Iterator<Item = Result<TokenWithContext, ScannerError>>,
    {
        // (Precedence, Prefix, Infix)
        match token {
            Token::LeftParen => (Precedence::Call, Some(Parser::grouping), None),
            Token::RightParen => (Precedence::None, None, None),
            Token::Comma => (Precedence::None, None, None),
            Token::Dot => (Precedence::Call, None, None),
            Token::Minus => (
                Precedence::Term,
                Some(Parser::unary),
                Some(Parser::binary),
            ),
            Token::Plus => (Precedence::Term, None, Some(Parser::binary)),
            Token::Slash => (Precedence::Factor, None, Some(Parser::binary)),
            Token::Star => (Precedence::Factor, None, Some(Parser::binary)),
            Token::Semicolon => (Precedence::None, None, None),
            Token::NumberLiteral(_) => (Precedence::None, Some(Parser::number), None),
            _ => unimplemented!(),
        }
    }

    fn parse_precedence(&mut self, precedence: Precedence) -> Result<(), ParsingError> {
        let prefix_function = {
            let peeked = self.peek().ok_or(ParsingError::UnexpectedEndOfFile)?;
            let (_, prefix_function, _) = Self::find_rule(&peeked.token);
            prefix_function
                .ok_or_else(|| ParsingError::Unexpected(peeked.lexeme.clone(), peeked.position))?
        };
        prefix_function(self)?;
        loop {
            let infix_function = {
                match self.peek() {
                    Some(peeked) => {
                        let (infix_rule_precedence, _, infix_function) =
                            Self::find_rule(&peeked.token);
                        if precedence <= infix_rule_precedence {
                            infix_function.ok_or_else(|| {
                                ParsingError::Unexpected(peeked.lexeme.clone(), peeked.position)
                            })?
                        } else {
                            return Ok(());
                        }
                    }
                    None => return Ok(()),
                }
            };
            infix_function(self)?;
        }
    }

    fn expression(&mut self) -> Result<(), ParsingError> {
        self.parse_precedence(Precedence::Assignment)
    }

    fn consume(&mut self, token: Token) -> Result<(), ParsingError> {
        let current = self.advance().ok_or(ParsingError::UnexpectedEndOfFile)?;
        if current.token == token {
            Ok(())
        } else {
            Err(ParsingError::Unexpected(
                current.lexeme.clone(),
                current.position,
            ))
        }
    }

    fn number(&mut self) -> Result<(), ParsingError> {
        let current = self.advance();
        let (value, line) = if let Some(ref t) = current {
            if let Token::NumberLiteral(ref n) = t.token {
                (*n, t.position.line)
            } else {
                unreachable!()
            }
        } else {
            panic!()
        };
        let constant = self.chunk.add_constant(value);
        self.chunk.add_instruction(OpCode::Constant(constant), line);
        Ok(())
    }

    fn grouping(&mut self) -> Result<(), ParsingError> {
        let _ = self.consume(Token::LeftParen)?;
        self.expression()?;
        self.consume(Token::RightParen)
    }

    fn unary(&mut self) -> Result<(), ParsingError> {
        let (opcode, line) = match self.advance() {
            Some(TokenWithContext {
                token: Token::Minus,
                position,
                lexeme: _,
            }) => (OpCode::Negate, position.line),
            _ => unreachable!("This code is executed only when we know we have a unary expression"),
        };
        let _ = self.parse_precedence(Precedence::Unary)?;
        self.emit(opcode, line);
        Ok(())
    }

    fn binary(&mut self) -> Result<(), ParsingError> {
        let (opcode, line) = match self.advance() {
            Some(TokenWithContext {
                token: Token::Plus,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Add), position.line),
            Some(TokenWithContext {
                token: Token::Minus,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Subtract), position.line),
            Some(TokenWithContext {
                token: Token::Star,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Multiply), position.line),
            Some(TokenWithContext {
                token: Token::Slash,
                position,
                lexeme: _,
            }) => (OpCode::Binary(BinaryOp::Divide), position.line),
            _ => {
                unreachable!("This code is executed only when we know we have a binary expression")
            }
        };
        let precedence = {
            let peeked = self
                .peek()
                .ok_or_else(|| ParsingError::UnexpectedEndOfFile)?;
            let (precedence, _, _) = Self::find_rule(&peeked.token);
            precedence.next()
        };
        self.parse_precedence(precedence)?;
        self.emit(opcode, line);
        Ok(())
    }

    fn parse(&mut self) -> Result<(), ()> {
        loop {
            match self.expression() {
                Ok(()) => return Ok(()),
                Err(error) => {
                    self.errors.push(CompilationError::ParsingError(error))
                    //TODO: add recovery mode
                }
            }
        }
    }
}

pub fn compile(text: &str) -> Result<Chunk, ()> {
    let mut chunk = Chunk::new();
    let tokens = scan_into_iterator(text);
    {
        let mut parser = Parser::new(&mut chunk, tokens);
        parser.parse()?;
        // TODO: assert that we consumed everything
        parser.emit(OpCode::Return, 0); // Line is meaningless
    }
    Ok(chunk)
}
<|endoftext|>


<commit_before>#![feature(slice_patterns)]

extern crate glium;
use glium::DisplayBuild;

extern crate fps_counter;
extern crate time;

use std::cell::{Cell, RefCell};
use std::path::PathBuf;

#[macro_use]
extern crate r3;
pub use r3::{cfg, ui};
use r3::glyph::GlyphCache;

use ui::Px;
use ui::color::Scheme;
use ui::draw::DrawCx;
use ui::event::Dispatch;
use ui::tab::Tab;
use ui::text::FontFaces;

#[cfg(not(feature = "ide"))]
fn main() { error__please_enable_the_ide_feature_for_rid3 }

#[cfg(feature = "ide")]
fn main() {
    r3::ide::rustc::init_env();

    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(800, 600)
        .with_title(String::from("rid3"))
        .build_glium()
        .unwrap();

    let renderer = &mut ui::render::Renderer::new(&display, FontFaces {
        regular: GlyphCache::from_data(include_bytes!("../../assets/NotoSans/NotoSans-Regular.ttf"), display.clone()).unwrap(),
        mono: GlyphCache::from_data(include_bytes!("../../assets/Hasklig/Hasklig-Regular.otf"), display.clone()).unwrap(),
        mono_bold: GlyphCache::from_data(include_bytes!("../../assets/Hasklig/Hasklig-Bold.otf"), display.clone()).unwrap()
    });

    let open_queue = RefCell::new(std::env::args().skip(1).map(PathBuf::from).collect::<Vec<_>>());
    let save_current = Cell::new(false);
    let run_current = Cell::new(false);
    let close_current = Cell::new(false);

    let tool_bar = tool_bar![
        ui::tool::Button::new("Open", || {
            open_queue.borrow_mut().extend(ui::dialog::open_file().into_iter())
        }),
        ui::tool::Button::new("Save", || save_current.set(true)),
        ui::tool::Button::new("Run", || {
            save_current.set(true);
            run_current.set(true);
        }),
        ui::tool::Button::new("Close", || close_current.set(true))
    ];
    let mut root = flow![down: tool_bar, ui::tab::Set::<ui::editor::Editor>::new()];

    let (mut x, mut y) = (0.0, 0.0);
    let mut key_tracker = ui::event::KeyTracker::default();
    let mut last_update = time::precise_time_ns();
    let mut cursor = ui::draw::MouseCursor::Default;
    let mut fps_counter = fps_counter::FPSCounter::new();

    // Ready the buffers.
    display.draw().finish().unwrap();
    let mut dirty = true;
    'main: loop {
        use glium::glutin::Event as E;
        use glium::glutin::{ElementState, MouseButton, MouseScrollDelta};

        for event in display.poll_events() {
            dirty |= match event {
                E::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                    dirty |= root.dispatch(&ui::event::KeyDown(key));
                    for e in key_tracker.down(key) {
                        dirty |= root.dispatch(&e);
                    }
                    false
                }
                E::KeyboardInput(ElementState::Released, _, Some(key)) => {
                    dirty |= root.dispatch(&ui::event::KeyUp(key));
                    for e in key_tracker.up(key) {
                        dirty |= root.dispatch(&e);
                    }
                    false
                }
                E::MouseInput(ElementState::Pressed, MouseButton::Left) => {
                    root.dispatch(&ui::event::MouseDown::new(x, y))
                }
                E::MouseInput(ElementState::Released, MouseButton::Left) => {
                    root.dispatch(&ui::event::MouseUp::new(x, y))
                }
                E::MouseMoved((nx, ny)) => {
                    x = nx as Px;
                    y = ny as Px;
                    root.dispatch(&ui::event::MouseMove::new(x, y))
                }
                // FIXME Convert lines into pixels, or vice-versa.
                E::MouseWheel(MouseScrollDelta::LineDelta(dx, dy)) |
                E::MouseWheel(MouseScrollDelta::PixelDelta(dx, dy)) => {
                    root.dispatch(&ui::event::MouseScroll::with(x, y,
                        ui::event::mouse::Scroll([dx as Px, dy as Px])))
                }
                E::ReceivedCharacter(c) => {
                    root.dispatch(&ui::event::TextInput(c))
                }
                E::Resized(..) => true,
                E::Closed => break 'main,
                _ => false
            }
        }

        let current = time::precise_time_ns();
        let dt = (current - last_update) as f32 / 1e9;
        dirty |= root.dispatch(&ui::event::Update(dt));
        for e in key_tracker.update(dt) {
            dirty |= root.dispatch(&e);
        }
        last_update = current;

        if save_current.get() {
            root.kids.1.current_mut().map(|e| e.save());
            save_current.set(false);
            dirty = true;
        }

        if run_current.get() {
            root.kids.1.current().map(|e| {
                println!("{}", std::iter::repeat('\n').take(200).collect::<String>());
                r3::ide::rustc::compile_and_run(e.path());
            });
            run_current.set(false);
        }

        if close_current.get() {
            let is_unsaved = root.kids.1.current().and_then(|e| {
                if e.is_saved() {
                    None
                } else {
                    Some(())
                }
            }).is_some();
            if is_unsaved {
                println!("Save file first!");
            } else {
                root.kids.1.remove();
                dirty = true;
            }
            close_current.set(false);
        }

        {
            let mut q = open_queue.borrow_mut();
            for file in q.drain(..) {
                root.kids.1.add(ui::editor::Editor::open(file));
                dirty = true;
            }
        }

        if dirty {
            let mut draw_cx = DrawCx::new(renderer, &display, display.draw());
            let [w, h] = draw_cx.dimensions();

            // TODO maybe integrate this with draw_cx?
            ui::layout::compute(&mut root, draw_cx.fonts(), w, h);

            draw_cx.clear(cfg::ColorScheme.background());
            draw_cx.draw(&root);

            let new_cursor = draw_cx.get_cursor();
            draw_cx.finish();

            if (new_cursor as usize) != (cursor as usize) {
                if !cfg!(windows) {
                    display.get_window().map(|w| w.set_cursor(new_cursor));
                }
                cursor = new_cursor;
            }

            let fps = fps_counter.tick();
            let tab_title = root.kids.1.current().map(|tab| tab.title());
            let title = format!("rid3: {} @ {}FPS", tab_title.as_ref().map_or("", |s| &s[..]), fps);
            display.get_window().map(|w| w.set_title(&title));

            dirty = false;
        } else {
            // Sleep for half a frame (assuming 60FPS).
            std::thread::sleep_ms(1000 / 120);
        }
    }
}
<commit_msg>Update rid3.rs<commit_after>#![feature(slice_patterns)]

extern crate glium;
use glium::DisplayBuild;

extern crate fps_counter;
extern crate time;

use std::cell::{Cell, RefCell};
use std::path::PathBuf;

#[macro_use]
extern crate rid3;
pub use rid3::{cfg, ui};
use rid3::glyph::GlyphCache;

use ui::Px;
use ui::color::Scheme;
use ui::draw::DrawCx;
use ui::event::Dispatch;
use ui::tab::Tab;
use ui::text::FontFaces;

#[cfg(not(feature = "ide"))]
fn main() { error__please_enable_the_ide_feature_for_rid3 }

#[cfg(feature = "ide")]
fn main() {
    rid3::ide::rustc::init_env();

    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(800, 600)
        .with_title(String::from("rid3"))
        .build_glium()
        .unwrap();

    let renderer = &mut ui::render::Renderer::new(&display, FontFaces {
        regular: GlyphCache::from_data(include_bytes!("../../assets/NotoSans/NotoSans-Regular.ttf"), display.clone()).unwrap(),
        mono: GlyphCache::from_data(include_bytes!("../../assets/Hasklig/Hasklig-Regular.otf"), display.clone()).unwrap(),
        mono_bold: GlyphCache::from_data(include_bytes!("../../assets/Hasklig/Hasklig-Bold.otf"), display.clone()).unwrap()
    });

    let open_queue = RefCell::new(std::env::args().skip(1).map(PathBuf::from).collect::<Vec<_>>());
    let save_current = Cell::new(false);
    let run_current = Cell::new(false);
    let close_current = Cell::new(false);

    let tool_bar = tool_bar![
        ui::tool::Button::new("Open", || {
            open_queue.borrow_mut().extend(ui::dialog::open_file().into_iter())
        }),
        ui::tool::Button::new("Save", || save_current.set(true)),
        ui::tool::Button::new("Run", || {
            save_current.set(true);
            run_current.set(true);
        }),
        ui::tool::Button::new("Close", || close_current.set(true))
    ];
    let mut root = flow![down: tool_bar, ui::tab::Set::<ui::editor::Editor>::new()];

    let (mut x, mut y) = (0.0, 0.0);
    let mut key_tracker = ui::event::KeyTracker::default();
    let mut last_update = time::precise_time_ns();
    let mut cursor = ui::draw::MouseCursor::Default;
    let mut fps_counter = fps_counter::FPSCounter::new();

    // Ready the buffers.
    display.draw().finish().unwrap();
    let mut dirty = true;
    'main: loop {
        use glium::glutin::Event as E;
        use glium::glutin::{ElementState, MouseButton, MouseScrollDelta};

        for event in display.poll_events() {
            dirty |= match event {
                E::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                    dirty |= root.dispatch(&ui::event::KeyDown(key));
                    for e in key_tracker.down(key) {
                        dirty |= root.dispatch(&e);
                    }
                    false
                }
                E::KeyboardInput(ElementState::Released, _, Some(key)) => {
                    dirty |= root.dispatch(&ui::event::KeyUp(key));
                    for e in key_tracker.up(key) {
                        dirty |= root.dispatch(&e);
                    }
                    false
                }
                E::MouseInput(ElementState::Pressed, MouseButton::Left) => {
                    root.dispatch(&ui::event::MouseDown::new(x, y))
                }
                E::MouseInput(ElementState::Released, MouseButton::Left) => {
                    root.dispatch(&ui::event::MouseUp::new(x, y))
                }
                E::MouseMoved((nx, ny)) => {
                    x = nx as Px;
                    y = ny as Px;
                    root.dispatch(&ui::event::MouseMove::new(x, y))
                }
                // FIXME Convert lines into pixels, or vice-versa.
                E::MouseWheel(MouseScrollDelta::LineDelta(dx, dy)) |
                E::MouseWheel(MouseScrollDelta::PixelDelta(dx, dy)) => {
                    root.dispatch(&ui::event::MouseScroll::with(x, y,
                        ui::event::mouse::Scroll([dx as Px, dy as Px])))
                }
                E::ReceivedCharacter(c) => {
                    root.dispatch(&ui::event::TextInput(c))
                }
                E::Resized(..) => true,
                E::Closed => break 'main,
                _ => false
            }
        }

        let current = time::precise_time_ns();
        let dt = (current - last_update) as f32 / 1e9;
        dirty |= root.dispatch(&ui::event::Update(dt));
        for e in key_tracker.update(dt) {
            dirty |= root.dispatch(&e);
        }
        last_update = current;

        if save_current.get() {
            root.kids.1.current_mut().map(|e| e.save());
            save_current.set(false);
            dirty = true;
        }

        if run_current.get() {
            root.kids.1.current().map(|e| {
                println!("{}", std::iter::repeat('\n').take(200).collect::<String>());
                rid3::ide::rustc::compile_and_run(e.path());
            });
            run_current.set(false);
        }

        if close_current.get() {
            let is_unsaved = root.kids.1.current().and_then(|e| {
                if e.is_saved() {
                    None
                } else {
                    Some(())
                }
            }).is_some();
            if is_unsaved {
                println!("Save file first!");
            } else {
                root.kids.1.remove();
                dirty = true;
            }
            close_current.set(false);
        }

        {
            let mut q = open_queue.borrow_mut();
            for file in q.drain(..) {
                root.kids.1.add(ui::editor::Editor::open(file));
                dirty = true;
            }
        }

        if dirty {
            let mut draw_cx = DrawCx::new(renderer, &display, display.draw());
            let [w, h] = draw_cx.dimensions();

            // TODO maybe integrate this with draw_cx?
            ui::layout::compute(&mut root, draw_cx.fonts(), w, h);

            draw_cx.clear(cfg::ColorScheme.background());
            draw_cx.draw(&root);

            let new_cursor = draw_cx.get_cursor();
            draw_cx.finish();

            if (new_cursor as usize) != (cursor as usize) {
                if !cfg!(windows) {
                    display.get_window().map(|w| w.set_cursor(new_cursor));
                }
                cursor = new_cursor;
            }

            let fps = fps_counter.tick();
            let tab_title = root.kids.1.current().map(|tab| tab.title());
            let title = format!("rid3: {} @ {}FPS", tab_title.as_ref().map_or("", |s| &s[..]), fps);
            display.get_window().map(|w| w.set_title(&title));

            dirty = false;
        } else {
            // Sleep for half a frame (assuming 60FPS).
            std::thread::sleep_ms(1000 / 120);
        }
    }
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use rustc::middle::const_eval::lookup_const_by_id;
use rustc::middle::def::*;
use rustc_front::hir::*;
use rustc_front::util::is_comparison_binop;
use syntax::codemap::Span;
use syntax::ast::Lit_::*;

use utils::span_lint;

declare_lint! {
    pub BAD_BIT_MASK,
    Warn,
    "expressions of the form `_ & mask == select` that will only ever return `true` or `false` \
     (because in the example `select` containing bits that `mask` doesn't have)"
}

declare_lint! {
    pub INEFFECTIVE_BIT_MASK,
    Warn,
    "expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`"
}

/// Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`.
/// This cannot work because the bit that makes up the value two was
/// zeroed out by the bit-and with 1. So the formula for detecting if an
/// expression of the type  `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
/// `!=`, `>=`, `>`}) can be determined from the following table:
///
/// |Comparison  |Bit-Op|Example     |is always|Formula               |
/// |------------|------|------------|---------|----------------------|
/// |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
/// |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
/// |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
/// |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
/// |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`              |
/// |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
///
/// This lint is **deny** by default
///
/// There is also a lint that warns on ineffective masks that is *warn*
/// by default.
///
/// |Comparison|Bit-Op   |Example    |equals |Formula|
/// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|`¹ && m <= c`|
/// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|`¹ && m < c` |
///
/// `¹ power_of_two(c + 1)`
#[derive(Copy,Clone)]
pub struct BitMask;

impl LintPass for BitMask {
    fn get_lints(&self) -> LintArray {
        lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK)
    }
}

impl LateLintPass for BitMask {
    fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
        if let ExprBinary(ref cmp, ref left, ref right) = e.node {
            if is_comparison_binop(cmp.node) {
                fetch_int_literal(cx, right).map_or_else(||
                    fetch_int_literal(cx, left).map_or((), |cmp_val|
                        check_compare(cx, right, invert_cmp(cmp.node),
                                      cmp_val, &e.span)),
                    |cmp_opt| check_compare(cx, left, cmp.node, cmp_opt,
                                            &e.span))
            }
        }
    }
}

fn invert_cmp(cmp : BinOp_) -> BinOp_ {
    match cmp {
        BiEq => BiEq,
        BiNe => BiNe,
        BiLt => BiGt,
        BiGt => BiLt,
        BiLe => BiGe,
        BiGe => BiLe,
        _ => BiOr // Dummy
    }
}

fn check_compare(cx: &LateContext, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) {
    match bit_op.node {
        ExprBinary(ref op, ref left, ref right) => {
            if op.node != BiBitAnd && op.node != BiBitOr { return; }
            fetch_int_literal(cx, right).or_else(|| fetch_int_literal(
                cx, left)).map_or((), |mask| check_bit_mask(cx, op.node,
                                                            cmp_op, mask, cmp_value, span))
        },
        _ => ()
    }
}

fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_,
                  mask_value: u64, cmp_value: u64, span: &Span) {
    match cmp_op {
        BiEq | BiNe => match bit_op {
            BiBitAnd => if mask_value & cmp_value != cmp_value {
                if cmp_value != 0 {
                    span_lint(cx, BAD_BIT_MASK, *span, &format!(
                        "incompatible bit mask: `_ & {}` can never be equal to `{}`",
                        mask_value, cmp_value));
                }
            } else {
                if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero");
                }
            },
            BiBitOr => if mask_value | cmp_value != cmp_value {
                span_lint(cx, BAD_BIT_MASK, *span, &format!(
                    "incompatible bit mask: `_ | {}` can never be equal to `{}`",
                    mask_value, cmp_value));
            },
            _ => ()
        },
        BiLt | BiGe => match bit_op {
            BiBitAnd => if mask_value < cmp_value {
                span_lint(cx, BAD_BIT_MASK, *span, &format!(
                    "incompatible bit mask: `_ & {}` will always be lower than `{}`",
                    mask_value, cmp_value));
            } else {
                if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero");
                }
            },
            BiBitOr => if mask_value >= cmp_value {
                span_lint(cx, BAD_BIT_MASK, *span, &format!(
                    "incompatible bit mask: `_ | {}` will never be lower than `{}`",
                    mask_value, cmp_value));
            } else {
                check_ineffective_lt(cx, *span, mask_value, cmp_value, "|");
            },
            BiBitXor =>
                check_ineffective_lt(cx, *span, mask_value, cmp_value, "^"),
            _ => ()
        },
        BiLe | BiGt => match bit_op {
            BiBitAnd => if mask_value <= cmp_value {
                span_lint(cx, BAD_BIT_MASK, *span, &format!(
                    "incompatible bit mask: `_ & {}` will never be higher than `{}`",
                    mask_value, cmp_value));
            } else {
                if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero");
                }
            },
            BiBitOr => if mask_value > cmp_value {
                span_lint(cx, BAD_BIT_MASK, *span, &format!(
                    "incompatible bit mask: `_ | {}` will always be higher than `{}`",
                    mask_value, cmp_value));
            } else {
                check_ineffective_gt(cx, *span, mask_value, cmp_value, "|");
            },
            BiBitXor =>
                check_ineffective_gt(cx, *span, mask_value, cmp_value, "^"),
            _ => ()
        },
        _ => ()
    }
}

fn check_ineffective_lt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) {
    if c.is_power_of_two() && m < c {
        span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!(
            "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
            op, m, c));
    }
}

fn check_ineffective_gt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) {
    if (c + 1).is_power_of_two() && m <= c {
        span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!(
            "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
            op, m, c));
    }
}

fn fetch_int_literal(cx: &LateContext, lit : &Expr) -> Option<u64> {
    match lit.node {
        ExprLit(ref lit_ptr) => {
            if let &LitInt(value, _) = &lit_ptr.node {
                Option::Some(value) //TODO: Handle sign
            } else { Option::None }
        },
        ExprPath(_, _) => {
            // Important to let the borrow expire before the const lookup to avoid double
            // borrowing.
            let def_map = cx.tcx.def_map.borrow();
            match def_map.get(&lit.id) {
                Some(&PathResolution { base_def: DefConst(def_id), ..}) => Some(def_id),
                _ => None
            }
        }
        .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, Option::None))
        .and_then(|l| fetch_int_literal(cx, l)),
        _ => Option::None
    }
}
<commit_msg>fix dogfood<commit_after>use rustc::lint::*;
use rustc::middle::const_eval::lookup_const_by_id;
use rustc::middle::def::*;
use rustc_front::hir::*;
use rustc_front::util::is_comparison_binop;
use syntax::codemap::Span;
use syntax::ast::Lit_::*;

use utils::span_lint;

declare_lint! {
    pub BAD_BIT_MASK,
    Warn,
    "expressions of the form `_ & mask == select` that will only ever return `true` or `false` \
     (because in the example `select` containing bits that `mask` doesn't have)"
}

declare_lint! {
    pub INEFFECTIVE_BIT_MASK,
    Warn,
    "expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`"
}

/// Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`.
/// This cannot work because the bit that makes up the value two was
/// zeroed out by the bit-and with 1. So the formula for detecting if an
/// expression of the type  `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
/// `!=`, `>=`, `>`}) can be determined from the following table:
///
/// |Comparison  |Bit-Op|Example     |is always|Formula               |
/// |------------|------|------------|---------|----------------------|
/// |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
/// |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
/// |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
/// |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
/// |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`              |
/// |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
///
/// This lint is **deny** by default
///
/// There is also a lint that warns on ineffective masks that is *warn*
/// by default.
///
/// |Comparison|Bit-Op   |Example    |equals |Formula|
/// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|`¹ && m <= c`|
/// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|`¹ && m < c` |
///
/// `¹ power_of_two(c + 1)`
#[derive(Copy,Clone)]
pub struct BitMask;

impl LintPass for BitMask {
    fn get_lints(&self) -> LintArray {
        lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK)
    }
}

impl LateLintPass for BitMask {
    fn check_expr(&mut self, cx: &LateContext, e: &Expr) {
        if let ExprBinary(ref cmp, ref left, ref right) = e.node {
            if is_comparison_binop(cmp.node) {
                fetch_int_literal(cx, right).map_or_else(||
                    fetch_int_literal(cx, left).map_or((), |cmp_val|
                        check_compare(cx, right, invert_cmp(cmp.node),
                                      cmp_val, &e.span)),
                    |cmp_opt| check_compare(cx, left, cmp.node, cmp_opt,
                                            &e.span))
            }
        }
    }
}

fn invert_cmp(cmp : BinOp_) -> BinOp_ {
    match cmp {
        BiEq => BiEq,
        BiNe => BiNe,
        BiLt => BiGt,
        BiGt => BiLt,
        BiLe => BiGe,
        BiGe => BiLe,
        _ => BiOr // Dummy
    }
}

fn check_compare(cx: &LateContext, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) {
    if let ExprBinary(ref op, ref left, ref right) = bit_op.node {
        if op.node != BiBitAnd && op.node != BiBitOr {
            return;
        }
        fetch_int_literal(cx, right).or_else(|| fetch_int_literal(
            cx, left)).map_or((), |mask| check_bit_mask(cx, op.node,
                                                        cmp_op, mask, cmp_value, span))
    }
}

fn check_bit_mask(cx: &LateContext, bit_op: BinOp_, cmp_op: BinOp_,
                  mask_value: u64, cmp_value: u64, span: &Span) {
    match cmp_op {
        BiEq | BiNe => match bit_op {
            BiBitAnd => if mask_value & cmp_value != cmp_value {
                if cmp_value != 0 {
                    span_lint(cx, BAD_BIT_MASK, *span, &format!(
                        "incompatible bit mask: `_ & {}` can never be equal to `{}`",
                        mask_value, cmp_value));
                }
            } else {
                if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero");
                }
            },
            BiBitOr => if mask_value | cmp_value != cmp_value {
                span_lint(cx, BAD_BIT_MASK, *span, &format!(
                    "incompatible bit mask: `_ | {}` can never be equal to `{}`",
                    mask_value, cmp_value));
            },
            _ => ()
        },
        BiLt | BiGe => match bit_op {
            BiBitAnd => if mask_value < cmp_value {
                span_lint(cx, BAD_BIT_MASK, *span, &format!(
                    "incompatible bit mask: `_ & {}` will always be lower than `{}`",
                    mask_value, cmp_value));
            } else {
                if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero");
                }
            },
            BiBitOr => if mask_value >= cmp_value {
                span_lint(cx, BAD_BIT_MASK, *span, &format!(
                    "incompatible bit mask: `_ | {}` will never be lower than `{}`",
                    mask_value, cmp_value));
            } else {
                check_ineffective_lt(cx, *span, mask_value, cmp_value, "|");
            },
            BiBitXor =>
                check_ineffective_lt(cx, *span, mask_value, cmp_value, "^"),
            _ => ()
        },
        BiLe | BiGt => match bit_op {
            BiBitAnd => if mask_value <= cmp_value {
                span_lint(cx, BAD_BIT_MASK, *span, &format!(
                    "incompatible bit mask: `_ & {}` will never be higher than `{}`",
                    mask_value, cmp_value));
            } else {
                if mask_value == 0 {
                    span_lint(cx, BAD_BIT_MASK, *span, "&-masking with zero");
                }
            },
            BiBitOr => if mask_value > cmp_value {
                span_lint(cx, BAD_BIT_MASK, *span, &format!(
                    "incompatible bit mask: `_ | {}` will always be higher than `{}`",
                    mask_value, cmp_value));
            } else {
                check_ineffective_gt(cx, *span, mask_value, cmp_value, "|");
            },
            BiBitXor =>
                check_ineffective_gt(cx, *span, mask_value, cmp_value, "^"),
            _ => ()
        },
        _ => ()
    }
}

fn check_ineffective_lt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) {
    if c.is_power_of_two() && m < c {
        span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!(
            "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
            op, m, c));
    }
}

fn check_ineffective_gt(cx: &LateContext, span: Span, m: u64, c: u64, op: &str) {
    if (c + 1).is_power_of_two() && m <= c {
        span_lint(cx, INEFFECTIVE_BIT_MASK, span, &format!(
            "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
            op, m, c));
    }
}

fn fetch_int_literal(cx: &LateContext, lit : &Expr) -> Option<u64> {
    match lit.node {
        ExprLit(ref lit_ptr) => {
            if let &LitInt(value, _) = &lit_ptr.node {
                Option::Some(value) //TODO: Handle sign
            } else { Option::None }
        },
        ExprPath(_, _) => {
            // Important to let the borrow expire before the const lookup to avoid double
            // borrowing.
            let def_map = cx.tcx.def_map.borrow();
            match def_map.get(&lit.id) {
                Some(&PathResolution { base_def: DefConst(def_id), ..}) => Some(def_id),
                _ => None
            }
        }
        .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, Option::None))
        .and_then(|l| fetch_int_literal(cx, l)),
        _ => Option::None
    }
}
<|endoftext|>


<commit_before>use std::cmp;
#[cfg(feature = "unstable")]
use std::iter::RandomAccessIterator;
use super::size_hint;
use self::EitherOrBoth::{Right, Left, Both};

// ZipLongest originally written by SimonSapin,
// and dedicated to itertools https://github.com/rust-lang/rust/pull/19283

/// An iterator which iterates two other iterators simultaneously
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct ZipLongest<T, U> {
    a: T,
    b: U
}

impl<T, U> ZipLongest<T, U>
{
    /// Create a new ZipLongest iterator.
    pub fn new(a: T, b: U) -> ZipLongest<T, U>
    {
        ZipLongest{a: a, b: b}
    }
}

impl<A, B, T, U> Iterator for ZipLongest<T, U> where
    T: Iterator<Item=A>,
    U: Iterator<Item=B>,
{
    type Item = EitherOrBoth<A, B>;
    #[inline]
    fn next(&mut self) -> Option<EitherOrBoth<A, B>> {
        match (self.a.next(), self.b.next()) {
            (None, None) => None,
            (Some(a), None) => Some(Left(a)),
            (None, Some(b)) => Some(Right(b)),
            (Some(a), Some(b)) => Some(Both(a, b)),
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::max(self.a.size_hint(), self.b.size_hint())
    }
}

impl<A, B, T, U> DoubleEndedIterator for ZipLongest<T, U> where
    T: DoubleEndedIterator<Item=A> + ExactSizeIterator,
    U: DoubleEndedIterator<Item=B> + ExactSizeIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<EitherOrBoth<A, B>> {
        use std::cmp::Ordering::{Equal, Greater, Less};
        match self.a.len().cmp(&self.b.len()) {
            Equal => match (self.a.next_back(), self.b.next_back()) {
                (None, None) => None,
                (Some(a), Some(b)) => Some(Both(a, b)),
                // These can only happen if .len() is inconsistent with .next_back()
                (Some(a), None) => Some(Left(a)),
                (None, Some(b)) => Some(Right(b)),
            },
            Greater => self.a.next_back().map(Left),
            Less => self.b.next_back().map(Right),
        }
    }
}

#[cfg(feature = "unstable")]
impl<A, B, T, U> RandomAccessIterator for ZipLongest<T, U> where
    T: RandomAccessIterator<Item=A>,
    U: RandomAccessIterator<Item=B>,
{
    #[inline]
    fn indexable(&self) -> usize {
        cmp::max(self.a.indexable(), self.b.indexable())
    }

    #[inline]
    fn idx(&mut self, index: usize) -> Option<EitherOrBoth<A, B>> {
        match (self.a.idx(index), self.b.idx(index)) {
            (None, None) => None,
            (Some(a), None) => Some(Left(a)),
            (None, Some(b)) => Some(Right(b)),
            (Some(a), Some(b)) => Some(Both(a, b)),
        }
    }
}

impl<T, U> ExactSizeIterator for ZipLongest<T, U> where
    T: ExactSizeIterator,
    U: ExactSizeIterator,
{}

/// A value yielded by `ZipLongest`.
/// Contains one or two values,
/// depending on which of the input iterators are exhausted.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum EitherOrBoth<A, B> {
    /// Neither input iterator is exhausted yet, yielding two values.
    Both(A, B),
    /// The parameter iterator of `.zip_longest()` is exhausted,
    /// only yielding a value from the `self` iterator.
    Left(A),
    /// The `self` iterator of `.zip_longest()` is exhausted,
    /// only yielding a value from the parameter iterator.
    Right(B),
}
<commit_msg>Fix warning in zip_longest<commit_after>use std::cmp::Ordering::{Equal, Greater, Less};
#[cfg(feature = "unstable")]
use std::cmp;
#[cfg(feature = "unstable")]
use std::iter::RandomAccessIterator;
use super::size_hint;
use self::EitherOrBoth::{Right, Left, Both};

// ZipLongest originally written by SimonSapin,
// and dedicated to itertools https://github.com/rust-lang/rust/pull/19283

/// An iterator which iterates two other iterators simultaneously
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct ZipLongest<T, U> {
    a: T,
    b: U
}

impl<T, U> ZipLongest<T, U>
{
    /// Create a new ZipLongest iterator.
    pub fn new(a: T, b: U) -> ZipLongest<T, U>
    {
        ZipLongest{a: a, b: b}
    }
}

impl<A, B, T, U> Iterator for ZipLongest<T, U> where
    T: Iterator<Item=A>,
    U: Iterator<Item=B>,
{
    type Item = EitherOrBoth<A, B>;
    #[inline]
    fn next(&mut self) -> Option<EitherOrBoth<A, B>> {
        match (self.a.next(), self.b.next()) {
            (None, None) => None,
            (Some(a), None) => Some(Left(a)),
            (None, Some(b)) => Some(Right(b)),
            (Some(a), Some(b)) => Some(Both(a, b)),
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::max(self.a.size_hint(), self.b.size_hint())
    }
}

impl<A, B, T, U> DoubleEndedIterator for ZipLongest<T, U> where
    T: DoubleEndedIterator<Item=A> + ExactSizeIterator,
    U: DoubleEndedIterator<Item=B> + ExactSizeIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<EitherOrBoth<A, B>> {
        match self.a.len().cmp(&self.b.len()) {
            Equal => match (self.a.next_back(), self.b.next_back()) {
                (None, None) => None,
                (Some(a), Some(b)) => Some(Both(a, b)),
                // These can only happen if .len() is inconsistent with .next_back()
                (Some(a), None) => Some(Left(a)),
                (None, Some(b)) => Some(Right(b)),
            },
            Greater => self.a.next_back().map(Left),
            Less => self.b.next_back().map(Right),
        }
    }
}

#[cfg(feature = "unstable")]
impl<A, B, T, U> RandomAccessIterator for ZipLongest<T, U> where
    T: RandomAccessIterator<Item=A>,
    U: RandomAccessIterator<Item=B>,
{
    #[inline]
    fn indexable(&self) -> usize {
        cmp::max(self.a.indexable(), self.b.indexable())
    }

    #[inline]
    fn idx(&mut self, index: usize) -> Option<EitherOrBoth<A, B>> {
        match (self.a.idx(index), self.b.idx(index)) {
            (None, None) => None,
            (Some(a), None) => Some(Left(a)),
            (None, Some(b)) => Some(Right(b)),
            (Some(a), Some(b)) => Some(Both(a, b)),
        }
    }
}

impl<T, U> ExactSizeIterator for ZipLongest<T, U> where
    T: ExactSizeIterator,
    U: ExactSizeIterator,
{}

/// A value yielded by `ZipLongest`.
/// Contains one or two values,
/// depending on which of the input iterators are exhausted.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum EitherOrBoth<A, B> {
    /// Neither input iterator is exhausted yet, yielding two values.
    Both(A, B),
    /// The parameter iterator of `.zip_longest()` is exhausted,
    /// only yielding a value from the `self` iterator.
    Left(A),
    /// The `self` iterator of `.zip_longest()` is exhausted,
    /// only yielding a value from the parameter iterator.
    Right(B),
}
<|endoftext|>


<commit_before>use std::any::Any;

/// The trait that any component must implement to be usable by a [`World`](../struct.World.html).
pub trait Component: Any + Send + Sync {}

pub mod position;

pub use self::position::PositionComponent;
<commit_msg>Re-export some entity stuff.<commit_after>use std::any::Any;

/// The trait that any component must implement to be usable by a [`World`](../struct.World.html).
pub trait Component: Any + Send + Sync {}

pub mod position;

pub use self::position::{PositionComponent, Positional};
<|endoftext|>