<commit_before>use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "7979016aff545f7b41cc517031026020b340989d";

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail")
        || path_string.starts_with("tests/rust/src/test/compile-fail")
        || path_string.starts_with("tests/rust/src/test/rustfix")
    {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // Deprecated placement syntax
        "tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
        // Deprecated anonymous parameter syntax in traits
        "tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
        "tests/rust/src/test/ui/issues/issue-13105.rs" |
        "tests/rust/src/test/ui/issues/issue-13775.rs" |
        "tests/rust/src/test/ui/issues/issue-34074.rs" |
        // Deprecated await macro syntax
        "tests/rust/src/test/ui/async-await/await-macro.rs" |
        // 2015-style dyn that libsyntax rejects
        "tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
        // not actually test cases
        "tests/rust/src/test/ui/include-single-expr-helper.rs" |
        "tests/rust/src/test/ui/include-single-expr-helper-1.rs" |
        "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let request = reqwest::blocking::get(&url)?;
    let decoder = GzDecoder::new(request);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<commit_msg>Check http response for error code<commit_after>use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "7979016aff545f7b41cc517031026020b340989d";

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail")
        || path_string.starts_with("tests/rust/src/test/compile-fail")
        || path_string.starts_with("tests/rust/src/test/rustfix")
    {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // Deprecated placement syntax
        "tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
        // Deprecated anonymous parameter syntax in traits
        "tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
        "tests/rust/src/test/ui/issues/issue-13105.rs" |
        "tests/rust/src/test/ui/issues/issue-13775.rs" |
        "tests/rust/src/test/ui/issues/issue-34074.rs" |
        // Deprecated await macro syntax
        "tests/rust/src/test/ui/async-await/await-macro.rs" |
        // 2015-style dyn that libsyntax rejects
        "tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
        // not actually test cases
        "tests/rust/src/test/ui/include-single-expr-helper.rs" |
        "tests/rust/src/test/ui/include-single-expr-helper-1.rs" |
        "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let decoder = GzDecoder::new(response);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Write;

struct Test {
    repo: &'static str,
    name: &'static str,
    sha: &'static str,
    lock: Option<&'static str>,
}

const TEST_REPOS: &'static [Test] = &[
    Test {
        name: "cargo",
        repo: "https://github.com/rust-lang/cargo",
        sha: "fae9c539388f1b7c70c31fd0a21b5dd9cd071177",
        lock: None,
    },
    Test {
        name: "iron",
        repo: "https://github.com/iron/iron",
        sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
        lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
    },
];

fn main() {
    let args = env::args().collect::<Vec<_>>();
    let ref cargo = args[1];
    let out_dir = Path::new(&args[2]);
    let ref cargo = Path::new(cargo);

    for test in TEST_REPOS.iter().rev() {
        test_repo(cargo, out_dir, test);
    }
}

fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
    println!("testing {}", test.repo);
    let dir = clone_repo(test, out_dir);
    if let Some(lockfile) = test.lock {
        File::create(&dir.join("Cargo.lock")).expect("")
            .write_all(lockfile.as_bytes()).expect("");
    }
    if !run_cargo_test(cargo, &dir) {
        panic!("tests failed for {}", test.repo);
    }
}

fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
    let out_dir = out_dir.join(test.name);

    if !out_dir.join(".git").is_dir() {
        let status = Command::new("git")
            .arg("init")
            .arg(&out_dir)
            .status()
            .expect("");
        assert!(status.success());
    }

    // Try progressively deeper fetch depths to find the commit
    let mut found = false;
    for depth in &[0, 1, 10, 100, 1000, 100000] {
        if *depth > 0 {
            let status = Command::new("git")
                .arg("fetch")
                .arg(test.repo)
                .arg("master")
                .arg(&format!("--depth={}", depth))
                .current_dir(&out_dir)
                .status()
                .expect("");
            assert!(status.success());
        }

        let status = Command::new("git")
            .arg("reset")
            .arg(test.sha)
            .arg("--hard")
            .current_dir(&out_dir)
            .status()
            .expect("");

        if status.success() {
            found = true;
            break;
        }
    }

    if !found {
        panic!("unable to find commit {}", test.sha)
    }
    let status = Command::new("git")
        .arg("clean")
        .arg("-fdx")
        .current_dir(&out_dir)
        .status()
        .unwrap();
    assert!(status.success());

    out_dir
}

fn run_cargo_test(cargo_path: &Path, crate_path: &Path) -> bool {
    let status = Command::new(cargo_path)
        .arg("test")
        // Disable rust-lang/cargo's cross-compile tests
        .env("CFG_DISABLE_CROSS_TESTS", "1")
        .current_dir(crate_path)
        .status()
        .expect("");

    status.success()
}
<commit_msg>Update commit hash in cargotest<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Write;

struct Test {
    repo: &'static str,
    name: &'static str,
    sha: &'static str,
    lock: Option<&'static str>,
}

const TEST_REPOS: &'static [Test] = &[
    Test {
        name: "cargo",
        repo: "https://github.com/rust-lang/cargo",
        sha: "26288f799427f9cc6e8bdddd782a17a8156ebc64",
        lock: None,
    },
    Test {
        name: "iron",
        repo: "https://github.com/iron/iron",
        sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
        lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
    },
];

fn main() {
    let args = env::args().collect::<Vec<_>>();
    let ref cargo = args[1];
    let out_dir = Path::new(&args[2]);
    let ref cargo = Path::new(cargo);

    for test in TEST_REPOS.iter().rev() {
        test_repo(cargo, out_dir, test);
    }
}

fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
    println!("testing {}", test.repo);
    let dir = clone_repo(test, out_dir);
    if let Some(lockfile) = test.lock {
        File::create(&dir.join("Cargo.lock")).expect("")
            .write_all(lockfile.as_bytes()).expect("");
    }
    if !run_cargo_test(cargo, &dir) {
        panic!("tests failed for {}", test.repo);
    }
}

fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
    let out_dir = out_dir.join(test.name);

    if !out_dir.join(".git").is_dir() {
        let status = Command::new("git")
            .arg("init")
            .arg(&out_dir)
            .status()
            .expect("");
        assert!(status.success());
    }

    // Try progressively deeper fetch depths to find the commit
    let mut found = false;
    for depth in &[0, 1, 10, 100, 1000, 100000] {
        if *depth > 0 {
            let status = Command::new("git")
                .arg("fetch")
                .arg(test.repo)
                .arg("master")
                .arg(&format!("--depth={}", depth))
                .current_dir(&out_dir)
                .status()
                .expect("");
            assert!(status.success());
        }

        let status = Command::new("git")
            .arg("reset")
            .arg(test.sha)
            .arg("--hard")
            .current_dir(&out_dir)
            .status()
            .expect("");

        if status.success() {
            found = true;
            break;
        }
    }

    if !found {
        panic!("unable to find commit {}", test.sha)
    }
    let status = Command::new("git")
        .arg("clean")
        .arg("-fdx")
        .current_dir(&out_dir)
        .status()
        .unwrap();
    assert!(status.success());

    out_dir
}

fn run_cargo_test(cargo_path: &Path, crate_path: &Path) -> bool {
    let status = Command::new(cargo_path)
        .arg("test")
        // Disable rust-lang/cargo's cross-compile tests
        .env("CFG_DISABLE_CROSS_TESTS", "1")
        .current_dir(crate_path)
        .status()
        .expect("");

    status.success()
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use util::codec::{number, Datum};
use super::{Result, Error};

use std::collections::HashMap;
use std::cmp::Ordering;
use tipb::expression::{Expr, ExprType};

/// `Evaluator` evaluates `tipb::Expr`.
#[derive(Default)]
pub struct Evaluator {
    // column_id -> column_value
    row: HashMap<i64, Datum>,
}

impl Evaluator {
    pub fn insert(&mut self, col_id: i64, datum: Datum) {
        self.row.insert(col_id, datum);
    }

    /// Eval evaluates expr to a Datum.
    pub fn eval(&self, expr: &Expr) -> Result<Datum> {
        match expr.get_tp() {
            ExprType::Int64 => self.eval_int(expr),
            ExprType::Uint64 => self.eval_uint(expr),
            // maybe we should use take here?
            ExprType::String | ExprType::Bytes => Ok(Datum::Bytes(expr.get_val().to_vec())),
            ExprType::ColumnRef => self.eval_column_ref(expr),
            ExprType::LT => self.eval_lt(expr),
            ExprType::LE => self.eval_le(expr),
            ExprType::EQ => self.eval_eq(expr),
            ExprType::NE => self.eval_ne(expr),
            ExprType::GE => self.eval_ge(expr),
            ExprType::GT => self.eval_gt(expr),
            ExprType::NullEQ => self.eval_null_eq(expr),
            ExprType::And => self.eval_and(expr),
            ExprType::Or => self.eval_or(expr),
            ExprType::Float32 | ExprType::Float64 => unimplemented!(),
            _ => Ok(Datum::Null),
        }
    }

    fn eval_int(&self, expr: &Expr) -> Result<Datum> {
        let i = try!(number::decode_i64(expr.get_val()));
        Ok(Datum::I64(i))
    }

    fn eval_uint(&self, expr: &Expr) -> Result<Datum> {
        let u = try!(number::decode_u64(expr.get_val()));
        Ok(Datum::U64(u))
    }

    fn eval_column_ref(&self, expr: &Expr) -> Result<Datum> {
        let i = try!(number::decode_i64(expr.get_val()));
        self.row.get(&i).cloned().ok_or_else(|| Error::Eval(format!("column {} not found", i)))
    }

    fn eval_lt(&self, expr: &Expr) -> Result<Datum> {
        let cmp = try!(self.cmp_children(expr));
        Ok(cmp.map(|c| c < Ordering::Equal).into())
    }

    fn eval_le(&self, expr: &Expr) -> Result<Datum> {
        let cmp = try!(self.cmp_children(expr));
        Ok(cmp.map(|c| c <= Ordering::Equal).into())
    }

    fn eval_eq(&self, expr: &Expr) -> Result<Datum> {
        let cmp = try!(self.cmp_children(expr));
        Ok(cmp.map(|c| c == Ordering::Equal).into())
    }

    fn eval_ne(&self, expr: &Expr) -> Result<Datum> {
        let cmp = try!(self.cmp_children(expr));
        Ok(cmp.map(|c| c != Ordering::Equal).into())
    }

    fn eval_ge(&self, expr: &Expr) -> Result<Datum> {
        let cmp = try!(self.cmp_children(expr));
        Ok(cmp.map(|c| c >= Ordering::Equal).into())
    }

    fn eval_gt(&self, expr: &Expr) -> Result<Datum> {
        let cmp = try!(self.cmp_children(expr));
        Ok(cmp.map(|c| c > Ordering::Equal).into())
    }

    fn eval_null_eq(&self, expr: &Expr) -> Result<Datum> {
        let (left, right) = try!(self.eval_two_children(expr));
        let cmp = try!(left.cmp(&right));
        Ok((cmp == Ordering::Equal).into())
    }

    fn cmp_children(&self, expr: &Expr) -> Result<Option<Ordering>> {
        let (left, right) = try!(self.eval_two_children(expr));
        if left == Datum::Null || right == Datum::Null {
            return Ok(None);
        }
        left.cmp(&right).map(Some).map_err(From::from)
    }

    fn eval_two_children(&self, expr: &Expr) -> Result<(Datum, Datum)> {
        let l = expr.get_children().len();
        if l != 2 {
            return Err(Error::Expr(format!("need 2 operands but got {}", l)));
        }
        let children = expr.get_children();
        let left = try!(self.eval(&children[0]));
        let right = try!(self.eval(&children[1]));
        Ok((left, right))
    }

    fn eval_and(&self, expr: &Expr) -> Result<Datum> {
        self.eval_two_children_as_bool(expr)
            .map(|(l, r)| (l.unwrap_or(false) && r.unwrap_or(false)).into())
    }

    fn eval_or(&self, expr: &Expr) -> Result<Datum> {
        self.eval_two_children_as_bool(expr)
            .map(|(l, r)| (l.unwrap_or(false) || r.unwrap_or(false)).into())
    }

    fn eval_two_children_as_bool(&self, expr: &Expr) -> Result<(Option<bool>, Option<bool>)> {
        let (left, right) = try!(self.eval_two_children(expr));
        let left_bool = try!(eval_as_bool(&left));
        let right_bool = try!(eval_as_bool(&right));
        Ok((left_bool, right_bool))
    }
}

/// eval datum as bool, if expr is Null, then None is return.
fn eval_as_bool(datum: &Datum) -> Result<Option<bool>> {
    if *datum == Datum::Null {
        Ok(None)
    } else {
        let b = try!(datum.as_bool());
        Ok(Some(b))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use util::codec::{Datum, number};

    use tipb::expression::{Expr, ExprType};
    use protobuf::RepeatedField;

    fn datum_expr(datum: Datum) -> Expr {
        let mut expr = Expr::new();
        match datum {
            Datum::I64(i) => {
                expr.set_tp(ExprType::Int64);
                let mut buf = vec![0; 8];
                number::encode_i64(&mut buf, i).unwrap();
                expr.set_val(buf);
            }
            Datum::U64(u) => {
                expr.set_tp(ExprType::Uint64);
                let mut buf = vec![0; 8];
                number::encode_u64(&mut buf, u).unwrap();
                expr.set_val(buf);
            }
            Datum::Bytes(bs) => {
                expr.set_tp(ExprType::Bytes);
                expr.set_val(bs);
            }
            Datum::F32(_) => unimplemented!(),
            Datum::F64(_) => unimplemented!(),
            _ => expr.set_tp(ExprType::Null),
        };
        expr
    }

    fn col_expr(col_id: i64) -> Expr {
        let mut expr = Expr::new();
        expr.set_tp(ExprType::ColumnRef);
        let mut buf = vec![0; 8];
        number::encode_i64(&mut buf, col_id).unwrap();
        expr.set_val(buf);
        expr
    }

    fn bin_expr(left: Datum, right: Datum, tp: ExprType) -> Expr {
        bin_expr_r(datum_expr(left), datum_expr(right), tp)
    }

    fn bin_expr_r(left: Expr, right: Expr, tp: ExprType) -> Expr {
        let mut expr = Expr::new();
        expr.set_tp(tp);
        expr.set_children(RepeatedField::from_vec(vec![left, right]));
        expr
    }

    // TODO: add more tests.
    #[test]
    fn test_eval() {
        let tests = vec![
			(datum_expr(Datum::I64(1)), Datum::I64(1)),
			(datum_expr(Datum::U64(1)), Datum::U64(1)),
			(datum_expr(b"abc".as_ref().into()), b"abc".as_ref().into()),
			(datum_expr(Datum::Null), Datum::Null),
			(col_expr(1), Datum::I64(100)),
			(bin_expr(Datum::I64(100), Datum::I64(1), ExprType::LT), Datum::I64(0)),
			(bin_expr(Datum::I64(1), Datum::I64(100), ExprType::LT), Datum::I64(1)),
			(bin_expr(Datum::I64(100), Datum::Null, ExprType::LT), Datum::Null),
			(bin_expr(Datum::I64(100), Datum::I64(1), ExprType::LE), Datum::I64(0)),
			(bin_expr(Datum::I64(1), Datum::I64(1), ExprType::LE), Datum::I64(1)),
			(bin_expr(Datum::I64(100), Datum::Null, ExprType::LE), Datum::Null),
			(bin_expr(Datum::I64(100), Datum::I64(1), ExprType::EQ), Datum::I64(0)),
			(bin_expr(Datum::I64(100), Datum::I64(100), ExprType::EQ), Datum::I64(1)),
			(bin_expr(Datum::I64(100), Datum::Null, ExprType::EQ), Datum::Null),
			(bin_expr(Datum::I64(100), Datum::I64(100), ExprType::NE), Datum::I64(0)),
			(bin_expr(Datum::I64(100), Datum::I64(1), ExprType::NE), Datum::I64(1)),
			(bin_expr(Datum::I64(100), Datum::Null, ExprType::NE), Datum::Null),
			(bin_expr(Datum::I64(1), Datum::I64(100), ExprType::GE), Datum::I64(0)),
			(bin_expr(Datum::I64(100), Datum::I64(100), ExprType::GE), Datum::I64(1)),
			(bin_expr(Datum::I64(100), Datum::Null, ExprType::GE), Datum::Null),
			(bin_expr(Datum::I64(100), Datum::I64(100), ExprType::GT), Datum::I64(0)),
			(bin_expr(Datum::I64(100), Datum::I64(1), ExprType::GT), Datum::I64(1)),
			(bin_expr(Datum::I64(100), Datum::Null, ExprType::GT), Datum::Null),
			(bin_expr(Datum::I64(1), Datum::Null, ExprType::NullEQ), Datum::I64(0)),
			(bin_expr(Datum::Null, Datum::Null, ExprType::NullEQ), Datum::I64(1)),
			// logic operation
			(bin_expr(Datum::I64(0), Datum::I64(1), ExprType::And), Datum::I64(0)),
			(bin_expr(Datum::I64(1), Datum::I64(1), ExprType::And), Datum::I64(1)),
			(bin_expr(Datum::I64(1), Datum::Null, ExprType::And), Datum::I64(0)),
			(bin_expr(Datum::I64(0), Datum::I64(0), ExprType::Or), Datum::I64(0)),
			(bin_expr(Datum::I64(0), Datum::I64(1), ExprType::Or), Datum::I64(1)),
			(bin_expr(Datum::I64(1), Datum::Null, ExprType::Or), Datum::I64(1)),
			(bin_expr(Datum::Null, Datum::Null, ExprType::Or), Datum::I64(0)),
			(bin_expr_r(bin_expr(Datum::I64(1), Datum::I64(1), ExprType::EQ),
			 bin_expr(Datum::I64(1), Datum::I64(1), ExprType::EQ), ExprType::And), Datum::I64(1)),
        ];

        let mut xevaluator = Evaluator::default();
        xevaluator.insert(1, Datum::I64(100));
        for (expr, result) in tests {
            let res = xevaluator.eval(&expr);
            if res.is_err() {
                panic!("failed to eval {:?}: {:?}", expr, res);
            }
            let res = res.unwrap();
            if res != result {
                panic!("failed to eval {:?} expect {:?}, got {:?}",
                       expr,
                       result,
                       res);
            }
        }
    }
}
<commit_msg>util: fix and/or with null (#385)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use util::codec::{number, Datum};
use super::{Result, Error};

use std::collections::HashMap;
use std::cmp::Ordering;
use tipb::expression::{Expr, ExprType};

/// `Evaluator` evaluates `tipb::Expr`.
#[derive(Default)]
pub struct Evaluator {
    // column_id -> column_value
    row: HashMap<i64, Datum>,
}

impl Evaluator {
    pub fn insert(&mut self, col_id: i64, datum: Datum) {
        self.row.insert(col_id, datum);
    }

    /// Eval evaluates expr to a Datum.
    pub fn eval(&self, expr: &Expr) -> Result<Datum> {
        match expr.get_tp() {
            ExprType::Int64 => self.eval_int(expr),
            ExprType::Uint64 => self.eval_uint(expr),
            // maybe we should use take here?
            ExprType::String | ExprType::Bytes => Ok(Datum::Bytes(expr.get_val().to_vec())),
            ExprType::ColumnRef => self.eval_column_ref(expr),
            ExprType::LT => self.eval_lt(expr),
            ExprType::LE => self.eval_le(expr),
            ExprType::EQ => self.eval_eq(expr),
            ExprType::NE => self.eval_ne(expr),
            ExprType::GE => self.eval_ge(expr),
            ExprType::GT => self.eval_gt(expr),
            ExprType::NullEQ => self.eval_null_eq(expr),
            ExprType::And => self.eval_and(expr),
            ExprType::Or => self.eval_or(expr),
            ExprType::Float32 | ExprType::Float64 => unimplemented!(),
            _ => Ok(Datum::Null),
        }
    }

    fn eval_int(&self, expr: &Expr) -> Result<Datum> {
        let i = try!(number::decode_i64(expr.get_val()));
        Ok(Datum::I64(i))
    }

    fn eval_uint(&self, expr: &Expr) -> Result<Datum> {
        let u = try!(number::decode_u64(expr.get_val()));
        Ok(Datum::U64(u))
    }

    fn eval_column_ref(&self, expr: &Expr) -> Result<Datum> {
        let i = try!(number::decode_i64(expr.get_val()));
        self.row.get(&i).cloned().ok_or_else(|| Error::Eval(format!("column {} not found", i)))
    }

    fn eval_lt(&self, expr: &Expr) -> Result<Datum> {
        let cmp = try!(self.cmp_children(expr));
        Ok(cmp.map(|c| c < Ordering::Equal).into())
    }

    fn eval_le(&self, expr: &Expr) -> Result<Datum> {
        let cmp = try!(self.cmp_children(expr));
        Ok(cmp.map(|c| c <= Ordering::Equal).into())
    }

    fn eval_eq(&self, expr: &Expr) -> Result<Datum> {
        let cmp = try!(self.cmp_children(expr));
        Ok(cmp.map(|c| c == Ordering::Equal).into())
    }

    fn eval_ne(&self, expr: &Expr) -> Result<Datum> {
        let cmp = try!(self.cmp_children(expr));
        Ok(cmp.map(|c| c != Ordering::Equal).into())
    }

    fn eval_ge(&self, expr: &Expr) -> Result<Datum> {
        let cmp = try!(self.cmp_children(expr));
        Ok(cmp.map(|c| c >= Ordering::Equal).into())
    }

    fn eval_gt(&self, expr: &Expr) -> Result<Datum> {
        let cmp = try!(self.cmp_children(expr));
        Ok(cmp.map(|c| c > Ordering::Equal).into())
    }

    fn eval_null_eq(&self, expr: &Expr) -> Result<Datum> {
        let (left, right) = try!(self.eval_two_children(expr));
        let cmp = try!(left.cmp(&right));
        Ok((cmp == Ordering::Equal).into())
    }

    fn cmp_children(&self, expr: &Expr) -> Result<Option<Ordering>> {
        let (left, right) = try!(self.eval_two_children(expr));
        if left == Datum::Null || right == Datum::Null {
            return Ok(None);
        }
        left.cmp(&right).map(Some).map_err(From::from)
    }

    fn eval_two_children(&self, expr: &Expr) -> Result<(Datum, Datum)> {
        let l = expr.get_children().len();
        if l != 2 {
            return Err(Error::Expr(format!("need 2 operands but got {}", l)));
        }
        let children = expr.get_children();
        let left = try!(self.eval(&children[0]));
        let right = try!(self.eval(&children[1]));
        Ok((left, right))
    }

    fn eval_and(&self, expr: &Expr) -> Result<Datum> {
        self.eval_two_children_as_bool(expr)
            .map(|p| {
                match p {
                    (Some(true), Some(true)) => true.into(),
                    (Some(false), _) | (_, Some(false)) => false.into(),
                    _ => Datum::Null,
                }
            })
    }

    fn eval_or(&self, expr: &Expr) -> Result<Datum> {
        self.eval_two_children_as_bool(expr).map(|p| {
            match p {
                (Some(true), _) | (_, Some(true)) => true.into(),
                (Some(false), Some(false)) => false.into(),
                _ => Datum::Null,
            }
        })
    }

    fn eval_two_children_as_bool(&self, expr: &Expr) -> Result<(Option<bool>, Option<bool>)> {
        let (left, right) = try!(self.eval_two_children(expr));
        let left_bool = try!(eval_as_bool(&left));
        let right_bool = try!(eval_as_bool(&right));
        Ok((left_bool, right_bool))
    }
}

/// eval datum as bool, if expr is Null, then None is return.
fn eval_as_bool(datum: &Datum) -> Result<Option<bool>> {
    if *datum == Datum::Null {
        Ok(None)
    } else {
        let b = try!(datum.as_bool());
        Ok(Some(b))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use util::codec::{Datum, number};

    use tipb::expression::{Expr, ExprType};
    use protobuf::RepeatedField;

    fn datum_expr(datum: Datum) -> Expr {
        let mut expr = Expr::new();
        match datum {
            Datum::I64(i) => {
                expr.set_tp(ExprType::Int64);
                let mut buf = vec![0; 8];
                number::encode_i64(&mut buf, i).unwrap();
                expr.set_val(buf);
            }
            Datum::U64(u) => {
                expr.set_tp(ExprType::Uint64);
                let mut buf = vec![0; 8];
                number::encode_u64(&mut buf, u).unwrap();
                expr.set_val(buf);
            }
            Datum::Bytes(bs) => {
                expr.set_tp(ExprType::Bytes);
                expr.set_val(bs);
            }
            Datum::F32(_) => unimplemented!(),
            Datum::F64(_) => unimplemented!(),
            _ => expr.set_tp(ExprType::Null),
        };
        expr
    }

    fn col_expr(col_id: i64) -> Expr {
        let mut expr = Expr::new();
        expr.set_tp(ExprType::ColumnRef);
        let mut buf = vec![0; 8];
        number::encode_i64(&mut buf, col_id).unwrap();
        expr.set_val(buf);
        expr
    }

    fn bin_expr(left: Datum, right: Datum, tp: ExprType) -> Expr {
        bin_expr_r(datum_expr(left), datum_expr(right), tp)
    }

    fn bin_expr_r(left: Expr, right: Expr, tp: ExprType) -> Expr {
        let mut expr = Expr::new();
        expr.set_tp(tp);
        expr.set_children(RepeatedField::from_vec(vec![left, right]));
        expr
    }

    // TODO: add more tests.
    #[test]
    fn test_eval() {
        let tests = vec![
			(datum_expr(Datum::I64(1)), Datum::I64(1)),
			(datum_expr(Datum::U64(1)), Datum::U64(1)),
			(datum_expr(b"abc".as_ref().into()), b"abc".as_ref().into()),
			(datum_expr(Datum::Null), Datum::Null),
			(col_expr(1), Datum::I64(100)),
			(bin_expr(Datum::I64(100), Datum::I64(1), ExprType::LT), Datum::I64(0)),
			(bin_expr(Datum::I64(1), Datum::I64(100), ExprType::LT), Datum::I64(1)),
			(bin_expr(Datum::I64(100), Datum::Null, ExprType::LT), Datum::Null),
			(bin_expr(Datum::I64(100), Datum::I64(1), ExprType::LE), Datum::I64(0)),
			(bin_expr(Datum::I64(1), Datum::I64(1), ExprType::LE), Datum::I64(1)),
			(bin_expr(Datum::I64(100), Datum::Null, ExprType::LE), Datum::Null),
			(bin_expr(Datum::I64(100), Datum::I64(1), ExprType::EQ), Datum::I64(0)),
			(bin_expr(Datum::I64(100), Datum::I64(100), ExprType::EQ), Datum::I64(1)),
			(bin_expr(Datum::I64(100), Datum::Null, ExprType::EQ), Datum::Null),
			(bin_expr(Datum::I64(100), Datum::I64(100), ExprType::NE), Datum::I64(0)),
			(bin_expr(Datum::I64(100), Datum::I64(1), ExprType::NE), Datum::I64(1)),
			(bin_expr(Datum::I64(100), Datum::Null, ExprType::NE), Datum::Null),
			(bin_expr(Datum::I64(1), Datum::I64(100), ExprType::GE), Datum::I64(0)),
			(bin_expr(Datum::I64(100), Datum::I64(100), ExprType::GE), Datum::I64(1)),
			(bin_expr(Datum::I64(100), Datum::Null, ExprType::GE), Datum::Null),
			(bin_expr(Datum::I64(100), Datum::I64(100), ExprType::GT), Datum::I64(0)),
			(bin_expr(Datum::I64(100), Datum::I64(1), ExprType::GT), Datum::I64(1)),
			(bin_expr(Datum::I64(100), Datum::Null, ExprType::GT), Datum::Null),
			(bin_expr(Datum::I64(1), Datum::Null, ExprType::NullEQ), Datum::I64(0)),
			(bin_expr(Datum::Null, Datum::Null, ExprType::NullEQ), Datum::I64(1)),
			// logic operation
			(bin_expr(Datum::I64(0), Datum::I64(1), ExprType::And), Datum::I64(0)),
			(bin_expr(Datum::I64(1), Datum::I64(1), ExprType::And), Datum::I64(1)),
			(bin_expr(Datum::I64(1), Datum::Null, ExprType::And), Datum::Null),
			(bin_expr(Datum::Null, Datum::I64(0), ExprType::And), Datum::I64(0)),
			(bin_expr(Datum::Null, Datum::Null, ExprType::And), Datum::Null),
			(bin_expr(Datum::I64(0), Datum::I64(0), ExprType::Or), Datum::I64(0)),
			(bin_expr(Datum::I64(0), Datum::I64(1), ExprType::Or), Datum::I64(1)),
			(bin_expr(Datum::I64(1), Datum::Null, ExprType::Or), Datum::I64(1)),
			(bin_expr(Datum::Null, Datum::Null, ExprType::Or), Datum::Null),
			(bin_expr(Datum::Null, Datum::I64(0), ExprType::Or), Datum::Null),
			(bin_expr_r(bin_expr(Datum::I64(1), Datum::I64(1), ExprType::EQ),
			 bin_expr(Datum::I64(1), Datum::I64(1), ExprType::EQ), ExprType::And), Datum::I64(1)),
        ];

        let mut xevaluator = Evaluator::default();
        xevaluator.insert(1, Datum::I64(100));
        for (expr, result) in tests {
            let res = xevaluator.eval(&expr);
            if res.is_err() {
                panic!("failed to eval {:?}: {:?}", expr, res);
            }
            let res = res.unwrap();
            if res != result {
                panic!("failed to eval {:?} expect {:?}, got {:?}",
                       expr,
                       result,
                       res);
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>handle generic enums<commit_after><|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;
use std::{fmt, env, thread, time};

#[derive(Debug)]
enum ParameterMode {
  Position,
  Immediate,
  Relative
}

#[derive(Debug)]
enum OperationType {
  Add,
  Multiply,
  Input,
  Output,
  JumpIfTrue,
  JumpIfFalse,
  LessThan,
  Equals,
  SetRelativeBase,
  Halt
}

#[derive(Debug)]
struct Instruction {
  operation: OperationType,
  inputs: Vec<(ParameterMode, i64)>
}

#[derive(Debug, Copy, Clone)]
enum ProgramResult {
  Output(i64),
  WaitForInput,
  Halt,
}

#[derive(Debug, PartialEq, Copy, Clone)]
enum Tile {
  Empty,
  Wall,
  Block,
  HorizontalPaddle,
  Ball
}

impl fmt::Display for Tile {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    write!(f, "{}", match self {
      Tile::Empty => "  ",
      Tile::Wall => "##",
      Tile::Block => "[]",
      Tile::HorizontalPaddle => "==",
      Tile::Ball => "()",
    })
  }
}

type TileGrid = HashMap<(i64, i64), Tile>;

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("13.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn parse_instruction(numbers: &[i64]) -> Instruction {
  let instruction_code = numbers[0];
  let op_code = instruction_code % 100;

  let (operation, inputs_count) = match op_code {
    1 => (OperationType::Add, 3),
    2 => (OperationType::Multiply, 3),
    3 => (OperationType::Input, 1),
    4 => (OperationType::Output, 1),
    5 => (OperationType::JumpIfTrue, 2),
    6 => (OperationType::JumpIfFalse, 2),
    7 => (OperationType::LessThan, 3),
    8 => (OperationType::Equals, 3),
    9 => (OperationType::SetRelativeBase, 1),
    99 => (OperationType::Halt, 0),
    _ => panic!()
  };

  let get_parameter_mode = |i| {
    match (instruction_code - op_code) / 10i64.pow(2 + i as u32) % 10 {
      0 => ParameterMode::Position,
      1 => ParameterMode::Immediate,
      2 => ParameterMode::Relative,
      _ => panic!()
    }
  };

  Instruction {
    operation,
    inputs: (0..inputs_count)
      .map(|i| (get_parameter_mode(i), numbers[i + 1]))
      .collect()
  }
}

fn run_program(state: (&mut Vec<i64>, &mut usize, &mut usize), input: Option<i64>) -> ProgramResult {
  let (program, pointer, relative_base) = state;
  let mut input = input;

  fn extend_memory(program: &mut Vec<i64>, index: usize) {
    while index >= program.len() {
      program.push(0);
    }
  }

  fn get_instruction_input_index(
    program: &mut Vec<i64>,
    instruction: &Instruction,
    relative_base: usize,
    index: usize
  ) -> usize {
    match instruction.inputs[index] {
      (ParameterMode::Relative, d) => {
        let j = (relative_base as i64 + d) as usize;
        extend_memory(program, j);
        j
      },
      (_, j) => {
        extend_memory(program, j as usize);
        j as usize
      }
    }
  }

  fn get_instruction_input(
    program: &mut Vec<i64>,
    instruction: &Instruction,
    relative_base: usize,
    index: usize
  ) -> i64 {
    match instruction.inputs[index] {
      (ParameterMode::Immediate, value) => value,
      _ => {
        let j = get_instruction_input_index(program, instruction, relative_base, index);
        program[j]
      }
    }
  }

  while *pointer < program.len() {
    let init_pointer = *pointer;
    let instruction = parse_instruction(&program[*pointer..]);

    let (target_value, target_index) = {
      let mut get_input = |i| {
        get_instruction_input(program, &instruction, *relative_base, i)
      };

      let (target_value, output_index) = match instruction.operation {
        OperationType::Add => (Some(get_input(0) + get_input(1)), Some(2)),
        OperationType::Multiply => (Some(get_input(0) * get_input(1)), Some(2)),
        OperationType::Input => match input {
          Some(x) => {
            input = None;
            (Some(x), Some(0))
          },
          _ => return ProgramResult::WaitForInput
        },
        OperationType::Output => (Some(get_input(0)), None),
        OperationType::LessThan => (Some((get_input(0) < get_input(1)) as i64), Some(2)),
        OperationType::Equals => (Some((get_input(0) == get_input(1)) as i64), Some(2)),
        OperationType::JumpIfTrue => {
          if get_input(0) != 0 {
            *pointer = get_input(1) as usize;
          }

          (None, None)
        },
        OperationType::JumpIfFalse => {
          if get_input(0) == 0 {
            *pointer = get_input(1) as usize;
          }

          (None, None)
        },
        OperationType::SetRelativeBase => {
          *relative_base = (*relative_base as i64 + get_input(0)) as usize;
          (None, None)
        }
        OperationType::Halt => break
      };

      (
        target_value,
        output_index.map(|i| {
          get_instruction_input_index(program, &instruction, *relative_base, i)
        })
      )
    };

    if *pointer == init_pointer {
      *pointer += instruction.inputs.len() + 1;
    }

    if let Some(target_value) = target_value {
      if let Some(target_index) = target_index {
        extend_memory(program, target_index);
        program[target_index] = target_value;
      } else {
        return ProgramResult::Output(target_value);
      }
    }
  }

  ProgramResult::Halt
}

fn output_screen(state: (&mut Vec<i64>, &mut usize, &mut usize), input: Option<i64>) -> (TileGrid, Option<i64>, bool) {
  let mut result = TileGrid::new();
  let mut score = None;
  let mut input_iter = input.into_iter();
  let mut halted = false;

  loop {
    let mut get = |input| run_program((state.0, state.1, state.2), input);

    match (get(input_iter.next()), get(None), get(None)) {
      (ProgramResult::Output(x), ProgramResult::Output(y), ProgramResult::Output(value)) => {
        if (x, y) == (-1, 0) {
          score = Some(value);
        } else {
          result.insert((x, y), match value {
            0 => Tile::Empty,
            1 => Tile::Wall,
            2 => Tile::Block,
            3 => Tile::HorizontalPaddle,
            4 => Tile::Ball,
            _ => panic!()
          });
        }
      },
      (ProgramResult::WaitForInput, _, _) => break,
      (ProgramResult::Halt, _, _) => {
        halted = true;
        break;
      },
      _ => panic!()
    };
  }

  (result, score, halted)
}

fn render_screen(screen: &TileGrid) -> String {
  let mut result = String::new();
  let bounds = screen.keys().cloned()
    .fold((None, None, None, None), |(min_x, max_x, min_y, max_y), (x, y)| {
      (
        [min_x, Some(x)].into_iter().filter_map(|&x| x).min(),
        [max_x, Some(x)].into_iter().filter_map(|&x| x).max(),
        [min_y, Some(y)].into_iter().filter_map(|&y| y).min(),
        [max_y, Some(y)].into_iter().filter_map(|&y| y).max()
      )
    });

  if let (Some(min_x), Some(max_x), Some(min_y), Some(max_y)) = bounds {
    for y in min_y..=max_y {
      for x in min_x..=max_x {
        let tile = screen.get(&(x, y)).cloned().unwrap_or(Tile::Empty);

        result.push_str(&format!("{}", tile));
      }

      result.push('\n');
    }
  }

  result
}

fn play_game(program: &mut Vec<i64>, print: bool) -> i64 {
  fn get_tile_position(screen: &TileGrid, tile: Tile) -> (i64, i64) {
    screen.iter()
    .find(|&(_, &t)| t == tile)
    .map(|(&position, _)| position)
    .unwrap()
  }

  let (mut s1, mut s2) = (0, 0);
  let (mut screen, mut score, _) = output_screen((program, &mut s1, &mut s2), None);

  loop {
    let paddle_position = get_tile_position(&screen, Tile::HorizontalPaddle);
    let ball_position = get_tile_position(&screen, Tile::Ball);
    let joystick = (ball_position.0 - paddle_position.0).signum();
    let (screen_update, score_update, halted) = output_screen((program, &mut s1, &mut s2), Some(joystick));

    for (&(x, y), &tile) in screen_update.iter() {
      screen.insert((x, y), tile);
    }

    if let Some(_) = score_update {
      score = score_update;
    }

    if print {
      println!("// Score: {}\n{}\n", score.unwrap_or(0), render_screen(&screen));
      thread::sleep(time::Duration::from_millis(50));
    }

    if halted {
      break;
    }
  }

  score.unwrap_or(0)
}

fn main() {
  let input = get_input().unwrap();
  let numbers = input.split(',')
    .filter_map(|x| x.trim().parse::<i64>().ok())
    .collect::<Vec<_>>();

  let (screen, _, _) = output_screen((&mut numbers.clone(), &mut 0, &mut 0), None);
  let block_tile_count = screen.iter()
    .filter(|&(_, &tile)| match tile {
      Tile::Block => true,
      _ => false
    })
    .count();

  println!("Part 1: {}", block_tile_count);

  let mut program = numbers.clone();
  program[0] = 2;

  let print_game = env::args().any(|s| s == "--print");
  let score = play_game(&mut program, print_game);

  println!("Part 2: {}", score);
}
<commit_msg>Use intcode module for day 13 solution<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;
use std::{fmt, env, thread, time};

mod intcode;
use intcode::{run_program, ProgramResult, ProgramState};

#[derive(Debug, PartialEq, Copy, Clone)]
enum Tile {
  Empty,
  Wall,
  Block,
  HorizontalPaddle,
  Ball
}

impl fmt::Display for Tile {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    write!(f, "{}", match self {
      Tile::Empty => "  ",
      Tile::Wall => "##",
      Tile::Block => "[]",
      Tile::HorizontalPaddle => "==",
      Tile::Ball => "()",
    })
  }
}

type TileGrid = HashMap<(i64, i64), Tile>;

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("13.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn output_screen(state: &mut ProgramState, input: Option<i64>) -> (TileGrid, Option<i64>, bool) {
  let mut result = TileGrid::new();
  let mut score = None;
  let mut input_iter = input.into_iter();
  let mut halted = false;

  loop {
    let mut get = |input| run_program(state, input);

    match (get(input_iter.next()), get(None), get(None)) {
      (ProgramResult::Output(x), ProgramResult::Output(y), ProgramResult::Output(value)) => {
        if (x, y) == (-1, 0) {
          score = Some(value);
        } else {
          result.insert((x, y), match value {
            0 => Tile::Empty,
            1 => Tile::Wall,
            2 => Tile::Block,
            3 => Tile::HorizontalPaddle,
            4 => Tile::Ball,
            _ => panic!()
          });
        }
      },
      (ProgramResult::WaitForInput, _, _) => break,
      (ProgramResult::Halt, _, _) => {
        halted = true;
        break;
      },
      _ => panic!()
    };
  }

  (result, score, halted)
}

fn render_screen(screen: &TileGrid) -> String {
  let mut result = String::new();
  let bounds = screen.keys().cloned()
    .fold((None, None, None, None), |(min_x, max_x, min_y, max_y), (x, y)| {
      (
        [min_x, Some(x)].into_iter().filter_map(|&x| x).min(),
        [max_x, Some(x)].into_iter().filter_map(|&x| x).max(),
        [min_y, Some(y)].into_iter().filter_map(|&y| y).min(),
        [max_y, Some(y)].into_iter().filter_map(|&y| y).max()
      )
    });

  if let (Some(min_x), Some(max_x), Some(min_y), Some(max_y)) = bounds {
    for y in min_y..=max_y {
      for x in min_x..=max_x {
        let tile = screen.get(&(x, y)).cloned().unwrap_or(Tile::Empty);

        result.push_str(&format!("{}", tile));
      }

      result.push('\n');
    }
  }

  result
}

fn play_game(state: &mut ProgramState, print: bool) -> i64 {
  fn get_tile_position(screen: &TileGrid, tile: Tile) -> (i64, i64) {
    screen.iter()
    .find(|&(_, &t)| t == tile)
    .map(|(&position, _)| position)
    .unwrap()
  }

  let (mut screen, mut score, _) = output_screen(state, None);

  loop {
    let paddle_position = get_tile_position(&screen, Tile::HorizontalPaddle);
    let ball_position = get_tile_position(&screen, Tile::Ball);
    let joystick = (ball_position.0 - paddle_position.0).signum();
    let (screen_update, score_update, halted) = output_screen(state, Some(joystick));

    for (&(x, y), &tile) in screen_update.iter() {
      screen.insert((x, y), tile);
    }

    if let Some(_) = score_update {
      score = score_update;
    }

    if print {
      println!("// Score: {}\n{}\n", score.unwrap_or(0), render_screen(&screen));
      thread::sleep(time::Duration::from_millis(50));
    }

    if halted {
      break;
    }
  }

  score.unwrap_or(0)
}

fn main() {
  let input = get_input().unwrap();
  let numbers = input.split(',')
    .filter_map(|x| x.trim().parse::<i64>().ok())
    .collect::<Vec<_>>();

  let (screen, _, _) = output_screen(&mut ProgramState::new(numbers.clone()), None);
  let block_tile_count = screen.iter()
    .filter(|&(_, &tile)| match tile {
      Tile::Block => true,
      _ => false
    })
    .count();

  println!("Part 1: {}", block_tile_count);

  let mut program = numbers.clone();
  program[0] = 2;

  let print_game = env::args().any(|s| s == "--print");
  let score = play_game(&mut ProgramState::new(program), print_game);

  println!("Part 2: {}", score);
}
<|endoftext|>


<commit_before>#![allow(unstable)]

use std::io::{self, fs};
use std::io::process::{Command, InheritFd};
use std::os;

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    assert!(cmd.stdout(InheritFd(1))
            .stderr(InheritFd(2))
            .status()
            .unwrap()
            .success());
}

fn main() {
    let cwd = os::getcwd().unwrap();

    let root_dir = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    let out_dir = Path::new(os::getenv("OUT_DIR").expect("out dir must be specified"));

    let build_dir = out_dir.join("build");
    assert!(fs::mkdir_recursive(&build_dir, io::USER_DIR).is_ok());
    assert!(os::change_dir(&build_dir).is_ok());

    let lib_dir = out_dir.join("lib");
    assert!(fs::mkdir_recursive(&lib_dir, io::USER_DIR).is_ok());

    run(Command::new("cmake")
        .arg(root_dir.join("forestdb"))
        .arg("-DCMAKE_BUILD_TYPE=Release") // FIXME: use env for determine type
        .arg(format!("-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={}", lib_dir.display()))
        .arg("-DSNAPPY_OPTION=Disable"));

    run(&mut Command::new("make"));

    let _ = os::change_dir(&cwd);

    println!("cargo:rustc-flags=-l forestdb -L {}", lib_dir.display());
}
<commit_msg>Building only lib + multicore<commit_after>#![allow(unstable)]

use std::io::{self, fs};
use std::io::process::{Command, InheritFd};
use std::os;

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    assert!(cmd.stdout(InheritFd(1))
            .stderr(InheritFd(2))
            .status()
            .unwrap()
            .success());
}

fn main() {
    let cwd = os::getcwd().unwrap();

    let root_dir = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    let out_dir = Path::new(os::getenv("OUT_DIR").expect("out dir must be specified"));

    let build_dir = out_dir.join("build");
    assert!(fs::mkdir_recursive(&build_dir, io::USER_DIR).is_ok());
    assert!(os::change_dir(&build_dir).is_ok());

    let lib_dir = out_dir.join("lib");
    assert!(fs::mkdir_recursive(&lib_dir, io::USER_DIR).is_ok());

    run(Command::new("cmake")
        .arg(root_dir.join("forestdb"))
        .arg("-DCMAKE_BUILD_TYPE=Release") // FIXME: use env for determine type
        .arg(format!("-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={}", lib_dir.display()))
        .arg("-DSNAPPY_OPTION=Disable"));

    run(Command::new("make")
        .arg("forestdb")
        .arg("-j")
        .arg("2")); // -j 2 is probably minimum

    let _ = os::change_dir(&cwd);

    println!("cargo:rustc-flags=-l forestdb -L {}", lib_dir.display());
}
<|endoftext|>


<commit_before>use super::{success_response, ApiResult};
use crate::{helpers::*, ApiError, UrlQuery};
use beacon_chain::{BeaconChain, BeaconChainTypes};
use bls::{PublicKey, Signature};
use hyper::{Body, Request};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use types::beacon_state::EthSpec;
use types::{Epoch, RelativeEpoch, Shard, Slot};

#[derive(Debug, Serialize, Deserialize)]
pub struct ValidatorDuty {
    /// The validator's BLS public key, uniquely identifying them. _48-bytes, hex encoded with 0x prefix, case insensitive._
    pub validator_pubkey: String,
    /// The slot at which the validator must attest.
    pub attestation_slot: Option<Slot>,
    /// The shard in which the validator must attest.
    pub attestation_shard: Option<Shard>,
    /// The slot in which a validator must propose a block, or `null` if block production is not required.
    pub block_proposal_slot: Option<Slot>,
}

impl ValidatorDuty {
    pub fn new() -> ValidatorDuty {
        ValidatorDuty {
            validator_pubkey: "".to_string(),
            attestation_slot: None,
            attestation_shard: None,
            block_proposal_slot: None,
        }
    }
}

/// HTTP Handler to retrieve a the duties for a set of validators during a particular epoch
pub fn get_validator_duties<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
    // Get beacon state
    let beacon_chain = req
        .extensions()
        .get::<Arc<BeaconChain<T>>>()
        .ok_or_else(|| ApiError::ServerError("Beacon chain extension missing".to_string()))?;
    //TODO Surely this state_cache thing is not necessary?
    let _ = beacon_chain
        .ensure_state_caches_are_built()
        .map_err(|e| ApiError::ServerError(format!("Unable to build state caches: {:?}", e)))?;
    let head_state = &beacon_chain.head().beacon_state;

    // Parse and check query parameters
    let query = UrlQuery::from_request(&req)?;
    let current_epoch = head_state.current_epoch();
    let epoch = match query.first_of(&["epoch"]) {
        Ok((_, v)) => Epoch::new(v.parse::<u64>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("Invalid epoch parameter, must be a u64. {:?}", e))
        })?),
        Err(_) => {
            // epoch not supplied, use the current epoch
            current_epoch
        }
    };
    let relative_epoch = RelativeEpoch::from_epoch(current_epoch, epoch).map_err(|e| {
        ApiError::InvalidQueryParams(format!(
            "Cannot get RelativeEpoch, epoch out of range: {:?}",
            e
        ))
    })?;
    let validators: Vec<PublicKey> = match query.all_of("validator_pubkeys") {
        Ok(v) => v
            .iter()
            .map(|pk| parse_pubkey(pk))
            .collect::<Result<Vec<_>, _>>()?,
        Err(e) => {
            return Err(e);
        }
    };
    let mut duties: Vec<ValidatorDuty> = Vec::new();

    // Get a list of all validators for this epoch
    let validator_proposers: Vec<usize> = epoch
        .slot_iter(T::EthSpec::slots_per_epoch())
        .map(|slot| {
            head_state
                .get_beacon_proposer_index(slot, relative_epoch, &beacon_chain.spec)
                .map_err(|e| {
                    ApiError::ServerError(format!(
                        "Unable to get proposer index for validator: {:?}",
                        e
                    ))
                })
        })
        .collect::<Result<Vec<usize>, _>>()?;

    // Look up duties for each validator
    for val_pk in validators {
        let mut duty = ValidatorDuty::new();
        duty.validator_pubkey = val_pk.as_hex_string();

        // Get the validator index
        // If it does not exist in the index, just add a null duty and move on.
        let val_index: usize = match head_state.get_validator_index(&val_pk) {
            Ok(Some(i)) => i,
            Ok(None) => {
                duties.append(&mut vec![duty]);
                continue;
            }
            Err(e) => {
                return Err(ApiError::ServerError(format!(
                    "Unable to read validator index cache. {:?}",
                    e
                )));
            }
        };

        // Set attestation duties
        match head_state.get_attestation_duties(val_index, relative_epoch) {
            Ok(Some(d)) => {
                duty.attestation_slot = Some(d.slot);
                duty.attestation_shard = Some(d.shard);
            }
            Ok(None) => {}
            Err(e) => {
                return Err(ApiError::ServerError(format!(
                    "unable to read cache for attestation duties: {:?}",
                    e
                )))
            }
        };

        // If the validator is to propose a block, identify the slot
        if let Some(slot) = validator_proposers.iter().position(|&v| val_index == v) {
            duty.block_proposal_slot = Some(Slot::new(
                relative_epoch
                    .into_epoch(current_epoch)
                    .start_slot(T::EthSpec::slots_per_epoch())
                    .as_u64()
                    + slot as u64,
            ));
        }

        duties.append(&mut vec![duty]);
    }
    let body = Body::from(
        serde_json::to_string(&duties)
            .expect("We should always be able to serialize the duties we created."),
    );
    Ok(success_response(body))
}

/// HTTP Handler to produce a new BeaconBlock from the current state, ready to be signed by a validator.
pub fn get_new_beacon_block<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
    // Get beacon state
    let beacon_chain = req
        .extensions()
        .get::<Arc<BeaconChain<T>>>()
        .ok_or_else(|| ApiError::ServerError("Beacon chain extension missing".to_string()))?;
    //TODO Surely this state_cache thing is not necessary?
    let _ = beacon_chain
        .ensure_state_caches_are_built()
        .map_err(|e| ApiError::ServerError(format!("Unable to build state caches: {:?}", e)))?;

    let query = UrlQuery::from_request(&req)?;
    let slot = match query.first_of(&["slot"]) {
        Ok((_, v)) => Slot::new(v.parse::<u64>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("Invalid slot parameter, must be a u64. {:?}", e))
        })?),
        Err(e) => {
            return Err(e);
        }
    };
    let randao_reveal = match query.first_of(&["randao_reveal"]) {
        Ok((_, v)) => Signature::from_bytes(
            hex::decode(&v)
                .map_err(|e| {
                    ApiError::InvalidQueryParams(format!(
                        "Invalid hex string for randao_reveal: {:?}",
                        e
                    ))
                })?
                .as_slice(),
        )
        .map_err(|e| {
            ApiError::InvalidQueryParams(format!("randao_reveal is not a valid signature: {:?}", e))
        })?,
        Err(e) => {
            return Err(e);
        }
    };

    let new_block = match beacon_chain.produce_block(randao_reveal, slot) {
        Ok((block, _state)) => block,
        Err(e) => {
            return Err(ApiError::ServerError(format!(
                "Beacon node is not able to produce a block: {:?}",
                e
            )));
        }
    };

    let body = Body::from(
        serde_json::to_string(&new_block)
            .expect("We should always be able to serialize a new block that we produced."),
    );
    Ok(success_response(body))
}

/// HTTP Handler to produce a new Attestation from the current state, ready to be signed by a validator.
pub fn get_new_attestation<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
    // Get beacon state
    let beacon_chain = req
        .extensions()
        .get::<Arc<BeaconChain<T>>>()
        .ok_or_else(|| ApiError::ServerError("Beacon chain extension missing".to_string()))?;
    //TODO Surely this state_cache thing is not necessary?
    let _ = beacon_chain
        .ensure_state_caches_are_built()
        .map_err(|e| ApiError::ServerError(format!("Unable to build state caches: {:?}", e)))?;

    let query = UrlQuery::from_request(&req)?;
    let validator: PublicKey = match query.first_of(&["validator_pubkey"]) {
        Ok((_, v)) => parse_pubkey(v.as_str())?,
        Err(e) => {
            return Err(e);
        }
    };
    let poc_bit: bool = match query.first_of(&["poc_bit"]) {
        Ok((_, v)) => v.parse::<bool>().map_err(|e| ApiError::InvalidQueryParams(format!("poc_bit is not a valid boolean value: {:?}", e)))?,
        Err(e) => {
            return Err(e);
        }
    };
    //TODO: this is probably unnecessary if we're always doing it by current slot.
    let _slot = match query.first_of(&["slot"]) {
        Ok((_, v)) => {
            let requested_slot = v.parse::<u64>().map_err(|e| {
                ApiError::InvalidQueryParams(format!("Invalid slot parameter, must be a u64. {:?}", e))
            })?;
            let current_slot = beacon_chain.head().beacon_state.slot.as_u64();
            if requested_slot != current_slot {
                return Err(ApiError::InvalidQueryParams(format!("Attestation data can only be requested for the current slot ({:?}), not your requested slot ({:?})", current_slot, requested_slot)));
            }
            Slot::new(requested_slot)
        },
        Err(e) => {
            return Err(e);
        }
    };
    let shard: Shard = match query.first_of(&["shard"]) {
        Ok((_, v)) => v.parse::<u64>().map_err(|e| ApiError::InvalidQueryParams(format!("Shard is not a valid u64 value: {:?}", e)))?,
        Err(e) => {
            return Err(e);
        }
    };

    let attestation_data = match beacon_chain.produce_attestation_data(shard) {
        Ok(v) => v,
        Err(e) => {
            return Err(ApiError::ServerError(format!("Could not produce an attestation: {:?}", e)));
        }
    };

    //TODO: This is currently AttestationData, but should be IndexedAttestation?
    let body = Body::from(
        serde_json::to_string(&attestation_data)
            .expect("We should always be able to serialize a new attestation that we produced."),
    );
    Ok(success_response(body))
}
<commit_msg>WIP: Furthered attestation production for validator.<commit_after>use super::{success_response, ApiResult};
use crate::{helpers::*, ApiError, UrlQuery};
use beacon_chain::{BeaconChain, BeaconChainTypes};
use bls::{AggregateSignature, PublicKey, Signature};
use hyper::{Body, Request};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use types::beacon_state::EthSpec;
use types::{Attestation, BitList, Epoch, RelativeEpoch, Shard, Slot};

#[derive(Debug, Serialize, Deserialize)]
pub struct ValidatorDuty {
    /// The validator's BLS public key, uniquely identifying them. _48-bytes, hex encoded with 0x prefix, case insensitive._
    pub validator_pubkey: String,
    /// The slot at which the validator must attest.
    pub attestation_slot: Option<Slot>,
    /// The shard in which the validator must attest.
    pub attestation_shard: Option<Shard>,
    /// The slot in which a validator must propose a block, or `null` if block production is not required.
    pub block_proposal_slot: Option<Slot>,
}

impl ValidatorDuty {
    pub fn new() -> ValidatorDuty {
        ValidatorDuty {
            validator_pubkey: "".to_string(),
            attestation_slot: None,
            attestation_shard: None,
            block_proposal_slot: None,
        }
    }
}

/// HTTP Handler to retrieve a the duties for a set of validators during a particular epoch
pub fn get_validator_duties<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
    // Get beacon state
    let beacon_chain = req
        .extensions()
        .get::<Arc<BeaconChain<T>>>()
        .ok_or_else(|| ApiError::ServerError("Beacon chain extension missing".to_string()))?;
    //TODO Surely this state_cache thing is not necessary?
    let _ = beacon_chain
        .ensure_state_caches_are_built()
        .map_err(|e| ApiError::ServerError(format!("Unable to build state caches: {:?}", e)))?;
    let head_state = &beacon_chain.head().beacon_state;

    // Parse and check query parameters
    let query = UrlQuery::from_request(&req)?;
    let current_epoch = head_state.current_epoch();
    let epoch = match query.first_of(&["epoch"]) {
        Ok((_, v)) => Epoch::new(v.parse::<u64>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("Invalid epoch parameter, must be a u64. {:?}", e))
        })?),
        Err(_) => {
            // epoch not supplied, use the current epoch
            current_epoch
        }
    };
    let relative_epoch = RelativeEpoch::from_epoch(current_epoch, epoch).map_err(|e| {
        ApiError::InvalidQueryParams(format!(
            "Cannot get RelativeEpoch, epoch out of range: {:?}",
            e
        ))
    })?;
    let validators: Vec<PublicKey> = match query.all_of("validator_pubkeys") {
        Ok(v) => v
            .iter()
            .map(|pk| parse_pubkey(pk))
            .collect::<Result<Vec<_>, _>>()?,
        Err(e) => {
            return Err(e);
        }
    };
    let mut duties: Vec<ValidatorDuty> = Vec::new();

    // Get a list of all validators for this epoch
    let validator_proposers: Vec<usize> = epoch
        .slot_iter(T::EthSpec::slots_per_epoch())
        .map(|slot| {
            head_state
                .get_beacon_proposer_index(slot, relative_epoch, &beacon_chain.spec)
                .map_err(|e| {
                    ApiError::ServerError(format!(
                        "Unable to get proposer index for validator: {:?}",
                        e
                    ))
                })
        })
        .collect::<Result<Vec<usize>, _>>()?;

    // Look up duties for each validator
    for val_pk in validators {
        let mut duty = ValidatorDuty::new();
        duty.validator_pubkey = val_pk.as_hex_string();

        // Get the validator index
        // If it does not exist in the index, just add a null duty and move on.
        let val_index: usize = match head_state.get_validator_index(&val_pk) {
            Ok(Some(i)) => i,
            Ok(None) => {
                duties.append(&mut vec![duty]);
                continue;
            }
            Err(e) => {
                return Err(ApiError::ServerError(format!(
                    "Unable to read validator index cache. {:?}",
                    e
                )));
            }
        };

        // Set attestation duties
        match head_state.get_attestation_duties(val_index, relative_epoch) {
            Ok(Some(d)) => {
                duty.attestation_slot = Some(d.slot);
                duty.attestation_shard = Some(d.shard);
            }
            Ok(None) => {}
            Err(e) => {
                return Err(ApiError::ServerError(format!(
                    "unable to read cache for attestation duties: {:?}",
                    e
                )))
            }
        };

        // If the validator is to propose a block, identify the slot
        if let Some(slot) = validator_proposers.iter().position(|&v| val_index == v) {
            duty.block_proposal_slot = Some(Slot::new(
                relative_epoch
                    .into_epoch(current_epoch)
                    .start_slot(T::EthSpec::slots_per_epoch())
                    .as_u64()
                    + slot as u64,
            ));
        }

        duties.append(&mut vec![duty]);
    }
    let body = Body::from(
        serde_json::to_string(&duties)
            .expect("We should always be able to serialize the duties we created."),
    );
    Ok(success_response(body))
}

/// HTTP Handler to produce a new BeaconBlock from the current state, ready to be signed by a validator.
pub fn get_new_beacon_block<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
    // Get beacon state
    let beacon_chain = req
        .extensions()
        .get::<Arc<BeaconChain<T>>>()
        .ok_or_else(|| ApiError::ServerError("Beacon chain extension missing".to_string()))?;
    //TODO Surely this state_cache thing is not necessary?
    let _ = beacon_chain
        .ensure_state_caches_are_built()
        .map_err(|e| ApiError::ServerError(format!("Unable to build state caches: {:?}", e)))?;

    let query = UrlQuery::from_request(&req)?;
    let slot = match query.first_of(&["slot"]) {
        Ok((_, v)) => Slot::new(v.parse::<u64>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("Invalid slot parameter, must be a u64. {:?}", e))
        })?),
        Err(e) => {
            return Err(e);
        }
    };
    let randao_reveal = match query.first_of(&["randao_reveal"]) {
        Ok((_, v)) => Signature::from_bytes(
            hex::decode(&v)
                .map_err(|e| {
                    ApiError::InvalidQueryParams(format!(
                        "Invalid hex string for randao_reveal: {:?}",
                        e
                    ))
                })?
                .as_slice(),
        )
        .map_err(|e| {
            ApiError::InvalidQueryParams(format!("randao_reveal is not a valid signature: {:?}", e))
        })?,
        Err(e) => {
            return Err(e);
        }
    };

    let new_block = match beacon_chain.produce_block(randao_reveal, slot) {
        Ok((block, _state)) => block,
        Err(e) => {
            return Err(ApiError::ServerError(format!(
                "Beacon node is not able to produce a block: {:?}",
                e
            )));
        }
    };

    let body = Body::from(
        serde_json::to_string(&new_block)
            .expect("We should always be able to serialize a new block that we produced."),
    );
    Ok(success_response(body))
}

/// HTTP Handler to produce a new Attestation from the current state, ready to be signed by a validator.
pub fn get_new_attestation<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
    // Get beacon state
    let beacon_chain = req
        .extensions()
        .get::<Arc<BeaconChain<T>>>()
        .ok_or_else(|| ApiError::ServerError("Beacon chain extension missing".to_string()))?;
    //TODO Surely this state_cache thing is not necessary?
    let _ = beacon_chain
        .ensure_state_caches_are_built()
        .map_err(|e| ApiError::ServerError(format!("Unable to build state caches: {:?}", e)))?;
    let head_state = &beacon_chain.head().beacon_state;

    let query = UrlQuery::from_request(&req)?;
    let val_pk: PublicKey = match query.first_of(&["validator_pubkey"]) {
        Ok((_, v)) => parse_pubkey(v.as_str())?,
        Err(e) => {
            return Err(e);
        }
    };
    // Get the validator index from the supplied public key
    // If it does not exist in the index, we cannot continue.
    let val_index: usize = match head_state.get_validator_index(&val_pk) {
        Ok(Some(i)) => i,
        Ok(None) => {
            return Err(ApiError::InvalidQueryParams(
                "The provided validator public key does not correspond to a validator index."
                    .into(),
            ));
        }
        Err(e) => {
            return Err(ApiError::ServerError(format!(
                "Unable to read validator index cache. {:?}",
                e
            )));
        }
    };
    // Get the duties of the validator, to make sure they match up.
    // If they don't have duties this epoch, then return an error
    let val_duty = match head_state.get_attestation_duties(val_index, RelativeEpoch::Current) {
        Ok(Some(d)) => d,
        Ok(None) => {
            return Err(ApiError::InvalidQueryParams("No validator duties could be found for the requested validator. Cannot provide valid attestation.".into()));
        }
        Err(e) => {
            return Err(ApiError::ServerError(format!(
                "unable to read cache for attestation duties: {:?}",
                e
            )))
        }
    };

    // Check that we are requesting an attestation during the slot where it is relevant.
    let present_slot = match beacon_chain.read_slot_clock() {
        Some(s) => s,
        None => {
            return Err(ApiError::ServerError(
                "Beacon node is unable to determine present slot, either the state isn't generated or the chain hasn't begun.".into()
            ));
        }
    };
    if val_duty.slot != present_slot {
        return Err(ApiError::InvalidQueryParams(format!("Validator is only able to request an attestation during the slot they are allocated. Current slot: {:?}, allocated slot: {:?}", head_state.slot, val_duty.slot)));
    }

    // Parse the POC bit and insert it into the aggregation bits
    let poc_bit: bool = match query.first_of(&["poc_bit"]) {
        Ok((_, v)) => v.parse::<bool>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("poc_bit is not a valid boolean value: {:?}", e))
        })?,
        Err(e) => {
            return Err(e);
        }
    };
    let mut aggregation_bits: BitList<bool> = BitList::with_capacity(val_duty.committee_len)
        .expect("An empty BitList should always be created, or we have bigger problems.")
        .into();
    aggregation_bits.set(val_duty.committee_index, poc_bit);

    // Allow a provided slot parameter to check against the expected slot as a sanity check.
    // Presently, we don't support attestations at future or past slots.
    let _slot = match query.first_of(&["slot"]) {
        Ok((_, v)) => {
            let requested_slot = v.parse::<u64>().map_err(|e| {
                ApiError::InvalidQueryParams(format!(
                    "Invalid slot parameter, must be a u64. {:?}",
                    e
                ))
            })?;
            let current_slot = beacon_chain.head().beacon_state.slot.as_u64();
            if requested_slot != current_slot {
                return Err(ApiError::InvalidQueryParams(format!("Attestation data can only be requested for the current slot ({:?}), not your requested slot ({:?})", current_slot, requested_slot)));
            }
            Slot::new(requested_slot)
        }
        Err(ApiError::InvalidQueryParams(_)) => {
            // Just fill _slot with a dummy value for now, making the slot parameter optional
            // We'll get the real slot from the ValidatorDuty
            Slot::new(0)
        }
        Err(e) => {
            return Err(e);
        }
    };

    let shard: Shard = match query.first_of(&["shard"]) {
        Ok((_, v)) => v.parse::<u64>().map_err(|e| {
            ApiError::InvalidQueryParams(format!("Shard is not a valid u64 value: {:?}", e))
        })?,
        Err(e) => {
            // This is a mandatory parameter, return the error
            return Err(e);
        }
    };
    let attestation_data = match beacon_chain.produce_attestation_data(shard) {
        Ok(v) => v,
        Err(e) => {
            return Err(ApiError::ServerError(format!(
                "Could not produce an attestation: {:?}",
                e
            )));
        }
    };

    let attestation = Attestation {
        aggregation_bits,
        data: attestation_data,
        custody_bits: BitList::with_capacity(val_duty.committee_len)
            .expect("Should be able to create an empty BitList for the custody bits."),
        signature: AggregateSignature::new(),
    };

    //TODO: This is currently AttestationData, but should be IndexedAttestation?
    let body = Body::from(
        serde_json::to_string(&attestation)
            .expect("We should always be able to serialize a new attestation that we produced."),
    );
    Ok(success_response(body))
}
<|endoftext|>


<commit_before>//! Lints concerned with the grouping of digits with underscores in integral or
//! floating-point literal expressions.

use rustc::lint::*;
use syntax::ast::*;
use syntax_pos;
use utils::{span_help_and_lint, snippet_opt, in_external_macro};

/// **What it does:** Warns if a long integral constant does not contain underscores.
///
/// **Why is this bad?** Reading long numbers is difficult without separators.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// 61864918973511
/// ```
declare_lint! {
    pub UNREADABLE_LITERAL,
    Warn,
    "long integer literal without underscores"
}

/// **What it does:** Warns if an integral constant is grouped inconsistently with underscores.
///
/// **Why is this bad?** Readers may incorrectly interpret inconsistently grouped digits.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// 618_64_9189_73_511
/// ```
declare_lint! {
    pub INCONSISTENT_DIGIT_GROUPING,
    Warn,
    "integer literals with digits grouped inconsistently"
}

/// **What it does:** Warns if the digits of an integral constant are grouped into groups that
/// are too large.
///
/// **Why is this bad?** Negatively impacts readability.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// 6186491_8973511
/// ```
declare_lint! {
    pub LARGE_DIGIT_GROUPS,
    Warn,
    "grouping digits into groups that are too large"
}

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

impl LintPass for LiteralDigitGrouping {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNREADABLE_LITERAL, INCONSISTENT_DIGIT_GROUPING, LARGE_DIGIT_GROUPS)
    }
}

impl EarlyLintPass for LiteralDigitGrouping {
    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        if in_external_macro(cx, expr.span) {
            return;
        }

        match expr.node {
            ExprKind::Lit(ref lit) => self.check_lit(cx, lit),
            _ => (),
        }
    }
}

impl LiteralDigitGrouping {
    fn check_lit(&self, cx: &EarlyContext, lit: &Lit) {
        // Lint integral literals.
        if_let_chain! {[
            let LitKind::Int(..) = lit.node,
            let Some(src) = snippet_opt(cx, lit.span),
            let Some(firstch) = src.chars().next(),
            char::to_digit(firstch, 10).is_some()
        ], {
            let digits = LiteralDigitGrouping::get_digits(&src, false);

            LiteralDigitGrouping::do_lint(digits, cx, &lit.span);
        }}

        // Lint floating-point literals.
        if_let_chain! {[
            let LitKind::Float(..) = lit.node,
            let Some(src) = snippet_opt(cx, lit.span),
            let Some(firstch) = src.chars().next(),
            char::to_digit(firstch, 10).is_some()
        ], {
            let digits: Vec<&str> = LiteralDigitGrouping::get_digits(&src, true)
                .split_terminator('.')
                .collect();

            // Lint integral and fractional parts separately, and then check consistency of digit
            // groups if both pass.
            if let Some(integral_group_size) = LiteralDigitGrouping::do_lint(digits[0], cx, &lit.span) {
                if digits.len() > 1 {
                    // Lint the fractional part of literal just like integral part, but reversed.
                    let fractional_part = &digits[1].chars().rev().collect::<String>();
                    if let Some(fractional_group_size) = LiteralDigitGrouping::do_lint(fractional_part, cx, &lit.span) {
                        let consistent = match (integral_group_size, fractional_group_size) {
                            // No groups on either side of decimal point - good to go.
                            (0, 0) => true,
                            // Integral part has grouped digits, fractional part does not.
                            (_, 0) => digits[1].len() <= integral_group_size,
                            // Fractional part has grouped digits, integral part does not.
                            (0, _) => digits[0].len() <= fractional_group_size,
                            // Both parts have grouped digits. Groups should be the same size.
                            (_, _) => integral_group_size == fractional_group_size,
                        };

                        if !consistent {
                            span_help_and_lint(cx, INCONSISTENT_DIGIT_GROUPING, lit.span,
                                           "digits grouped inconsistently by underscores",
                                           "consider making each group three or four digits");
                        }
                    }
                }
            }
        }}
    }

    /// Returns the digits of an integral or floating-point literal.
    fn get_digits(lit: &str, float: bool) -> &str {
        // Determine delimiter for radix prefix, if present.
        let mb_r = if lit.starts_with("0x") {
            Some('x')
        } else if lit.starts_with("0b") {
            Some('b')
        } else if lit.starts_with("0o") {
            Some('o')
        } else {
            None
        };

        let has_suffix = !float && (lit.contains('i') || lit.contains('u')) || float && lit.contains('f');

        // Grab part of literal between the radix prefix and type suffix.
        let mut digits = if let Some(r) = mb_r {
            lit.split(|c| c == 'i' || c == 'u' || c == r || (float && c == 'f')).nth(1).unwrap()
        } else {
            lit.split(|c| c == 'i' || c == 'u' || (float && c == 'f')).next().unwrap()
        };

        // If there was an underscore before type suffix, drop it.
        if has_suffix && digits.chars().last().unwrap() == '_' {
            digits = digits.split_at(digits.len() - 1).0;
        }

        digits
    }

    /// Performs lint on `digits` (no decimal point) and returns the group size. `None` is
    /// returned when emitting a warning.
    fn do_lint(digits: &str, cx: &EarlyContext, span: &syntax_pos::Span) -> Option<usize> {
        // Grab underscore indices with respect to the units digit.
        let underscore_positions: Vec<usize> = digits.chars().rev().enumerate()
            .filter_map(|(idx, digit)|
                if digit == '_' {
                    Some(idx)
                } else {
                    None
                })
            .collect();

        if underscore_positions.is_empty() {
            // Check if literal needs underscores.
            if digits.len() > 4 {
                span_help_and_lint(cx, UNREADABLE_LITERAL, *span,
                                   "long literal lacking separators",
                                   "consider using underscores to make literal more readable");
                return None;
            } else {
                return Some(0);
            }
        } else {
            // Check consistency and the sizes of the groups.
            let group_size = underscore_positions[0];
            let consistent = underscore_positions
                .windows(2)
                .all(|ps| ps[1] - ps[0] == group_size + 1)
                // number of digits to the left of the last group cannot be bigger than group size.
                && (digits.len() - underscore_positions.last().unwrap() <= group_size + 1);

            if !consistent {
                span_help_and_lint(cx, INCONSISTENT_DIGIT_GROUPING, *span,
                                   "digits grouped inconsistently by underscores",
                                   "consider making each group three or four digits");
                return None;
            } else if group_size > 4 {
                span_help_and_lint(cx, LARGE_DIGIT_GROUPS, *span,
                                   "digit groups should be smaller",
                                   "consider using groups of three or four digits");
                return None;
            }
            return Some(group_size);
        }
    }
}
<commit_msg>Fix lint descriptions.<commit_after>//! Lints concerned with the grouping of digits with underscores in integral or
//! floating-point literal expressions.

use rustc::lint::*;
use syntax::ast::*;
use syntax_pos;
use utils::{span_help_and_lint, snippet_opt, in_external_macro};

/// **What it does:** Warns if a long integral or floating-point constant does not contain underscores.
///
/// **Why is this bad?** Reading long numbers is difficult without separators.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// 61864918973511
/// ```
declare_lint! {
    pub UNREADABLE_LITERAL,
    Warn,
    "long integer literal without underscores"
}

/// **What it does:** Warns if an integral or floating-point constant is grouped inconsistently with underscores.
///
/// **Why is this bad?** Readers may incorrectly interpret inconsistently grouped digits.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// 618_64_9189_73_511
/// ```
declare_lint! {
    pub INCONSISTENT_DIGIT_GROUPING,
    Warn,
    "integer literals with digits grouped inconsistently"
}

/// **What it does:** Warns if the digits of an integral or floating-point constant are grouped into groups that
/// are too large.
///
/// **Why is this bad?** Negatively impacts readability.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// 6186491_8973511
/// ```
declare_lint! {
    pub LARGE_DIGIT_GROUPS,
    Warn,
    "grouping digits into groups that are too large"
}

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

impl LintPass for LiteralDigitGrouping {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNREADABLE_LITERAL, INCONSISTENT_DIGIT_GROUPING, LARGE_DIGIT_GROUPS)
    }
}

impl EarlyLintPass for LiteralDigitGrouping {
    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        if in_external_macro(cx, expr.span) {
            return;
        }

        match expr.node {
            ExprKind::Lit(ref lit) => self.check_lit(cx, lit),
            _ => (),
        }
    }
}

impl LiteralDigitGrouping {
    fn check_lit(&self, cx: &EarlyContext, lit: &Lit) {
        // Lint integral literals.
        if_let_chain! {[
            let LitKind::Int(..) = lit.node,
            let Some(src) = snippet_opt(cx, lit.span),
            let Some(firstch) = src.chars().next(),
            char::to_digit(firstch, 10).is_some()
        ], {
            let digits = LiteralDigitGrouping::get_digits(&src, false);

            LiteralDigitGrouping::do_lint(digits, cx, &lit.span);
        }}

        // Lint floating-point literals.
        if_let_chain! {[
            let LitKind::Float(..) = lit.node,
            let Some(src) = snippet_opt(cx, lit.span),
            let Some(firstch) = src.chars().next(),
            char::to_digit(firstch, 10).is_some()
        ], {
            let digits: Vec<&str> = LiteralDigitGrouping::get_digits(&src, true)
                .split_terminator('.')
                .collect();

            // Lint integral and fractional parts separately, and then check consistency of digit
            // groups if both pass.
            if let Some(integral_group_size) = LiteralDigitGrouping::do_lint(digits[0], cx, &lit.span) {
                if digits.len() > 1 {
                    // Lint the fractional part of literal just like integral part, but reversed.
                    let fractional_part = &digits[1].chars().rev().collect::<String>();
                    if let Some(fractional_group_size) = LiteralDigitGrouping::do_lint(fractional_part, cx, &lit.span) {
                        let consistent = match (integral_group_size, fractional_group_size) {
                            // No groups on either side of decimal point - good to go.
                            (0, 0) => true,
                            // Integral part has grouped digits, fractional part does not.
                            (_, 0) => digits[1].len() <= integral_group_size,
                            // Fractional part has grouped digits, integral part does not.
                            (0, _) => digits[0].len() <= fractional_group_size,
                            // Both parts have grouped digits. Groups should be the same size.
                            (_, _) => integral_group_size == fractional_group_size,
                        };

                        if !consistent {
                            span_help_and_lint(cx, INCONSISTENT_DIGIT_GROUPING, lit.span,
                                           "digits grouped inconsistently by underscores",
                                           "consider making each group three or four digits");
                        }
                    }
                }
            }
        }}
    }

    /// Returns the digits of an integral or floating-point literal.
    fn get_digits(lit: &str, float: bool) -> &str {
        // Determine delimiter for radix prefix, if present.
        let mb_r = if lit.starts_with("0x") {
            Some('x')
        } else if lit.starts_with("0b") {
            Some('b')
        } else if lit.starts_with("0o") {
            Some('o')
        } else {
            None
        };

        let has_suffix = !float && (lit.contains('i') || lit.contains('u')) || float && lit.contains('f');

        // Grab part of literal between the radix prefix and type suffix.
        let mut digits = if let Some(r) = mb_r {
            lit.split(|c| c == 'i' || c == 'u' || c == r || (float && c == 'f')).nth(1).unwrap()
        } else {
            lit.split(|c| c == 'i' || c == 'u' || (float && c == 'f')).next().unwrap()
        };

        // If there was an underscore before type suffix, drop it.
        if has_suffix && digits.chars().last().unwrap() == '_' {
            digits = digits.split_at(digits.len() - 1).0;
        }

        digits
    }

    /// Performs lint on `digits` (no decimal point) and returns the group size. `None` is
    /// returned when emitting a warning.
    fn do_lint(digits: &str, cx: &EarlyContext, span: &syntax_pos::Span) -> Option<usize> {
        // Grab underscore indices with respect to the units digit.
        let underscore_positions: Vec<usize> = digits.chars().rev().enumerate()
            .filter_map(|(idx, digit)|
                if digit == '_' {
                    Some(idx)
                } else {
                    None
                })
            .collect();

        if underscore_positions.is_empty() {
            // Check if literal needs underscores.
            if digits.len() > 4 {
                span_help_and_lint(cx, UNREADABLE_LITERAL, *span,
                                   "long literal lacking separators",
                                   "consider using underscores to make literal more readable");
                return None;
            } else {
                return Some(0);
            }
        } else {
            // Check consistency and the sizes of the groups.
            let group_size = underscore_positions[0];
            let consistent = underscore_positions
                .windows(2)
                .all(|ps| ps[1] - ps[0] == group_size + 1)
                // number of digits to the left of the last group cannot be bigger than group size.
                && (digits.len() - underscore_positions.last().unwrap() <= group_size + 1);

            if !consistent {
                span_help_and_lint(cx, INCONSISTENT_DIGIT_GROUPING, *span,
                                   "digits grouped inconsistently by underscores",
                                   "consider making each group three or four digits");
                return None;
            } else if group_size > 4 {
                span_help_and_lint(cx, LARGE_DIGIT_GROUPS, *span,
                                   "digit groups should be smaller",
                                   "consider using groups of three or four digits");
                return None;
            }
            return Some(group_size);
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate nom;
#[macro_use] extern crate log;
extern crate env_logger;
extern crate mio;
extern crate rustc_serialize;
extern crate yxorp;
extern crate toml;

mod config;
mod command;
mod state;

use std::net::{UdpSocket,ToSocketAddrs};
use std::sync::mpsc::{channel};
use std::collections::HashMap;
use std::thread::JoinHandle;
use yxorp::network;
use yxorp::network::metrics::{METRICS,ProxyMetrics};

use command::{Listener,ListenerType};

fn main() {
  env_logger::init().unwrap();
  info!("starting up");

  // FIXME: should load configuration from a CLI argument
  if let Ok(config) = config::Config::load_from_path("./config.toml") {
    let metrics_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
    let metrics_host   = (&config.metrics.address[..], config.metrics.port).to_socket_addrs().unwrap().next().unwrap();
    METRICS.lock().unwrap().set_up_remote(metrics_socket, metrics_host);
    let metrics_guard = ProxyMetrics::run();

    let mut listeners = HashMap::new();
    let mut jh_opt: Option<JoinHandle<()>> = None;

    for (ref tag, ref ls) in config.listeners {
      let (sender, receiver) = channel::<network::ServerMessage>();
      let mut address = ls.address.clone();
      address.push(':');
      address.push_str(&ls.port.to_string());

      let (tx, jg) = match ls.listener_type {
        ListenerType::HTTP => {
          network::http::start_listener(address.parse().unwrap(), ls.max_connections, sender)
        },
        ListenerType::HTTPS => {
          network::tls::start_listener(address.parse().unwrap(), ls.max_connections, None, sender)
        },
        _ => unimplemented!()
      };
      let l =  Listener::new(tag.clone(), ls.listener_type, ls.address.clone(), ls.port, tx, receiver);
      listeners.insert(tag.clone(), l);
      jh_opt = Some(jg);
    };

    command::start(config.command_socket, listeners);
    if let Some(jh) = jh_opt {
      let _ = jh.join();
      info!("good bye");
    }
  } else {
    println!("could not load configuration, stopping");
  }
}

<commit_msg>Do not crash oninvalid addresses in configuration<commit_after>#[macro_use] extern crate nom;
#[macro_use] extern crate log;
extern crate env_logger;
extern crate mio;
extern crate rustc_serialize;
extern crate yxorp;
extern crate toml;

mod config;
mod command;
mod state;

use std::net::{UdpSocket,ToSocketAddrs};
use std::sync::mpsc::{channel};
use std::collections::HashMap;
use std::thread::JoinHandle;
use yxorp::network;
use yxorp::network::metrics::{METRICS,ProxyMetrics};

use command::{Listener,ListenerType};

fn main() {
  env_logger::init().unwrap();
  info!("starting up");

  // FIXME: should load configuration from a CLI argument
  if let Ok(config) = config::Config::load_from_path("./config.toml") {
    let metrics_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
    let metrics_host   = (&config.metrics.address[..], config.metrics.port).to_socket_addrs().unwrap().next().unwrap();
    METRICS.lock().unwrap().set_up_remote(metrics_socket, metrics_host);
    let metrics_guard = ProxyMetrics::run();

    let mut listeners = HashMap::new();
    let mut jh_opt: Option<JoinHandle<()>> = None;

    for (ref tag, ref ls) in config.listeners {
      let (sender, receiver) = channel::<network::ServerMessage>();
      let mut address = ls.address.clone();
      address.push(':');
      address.push_str(&ls.port.to_string());

      if let Ok(addr) = address.parse() {
        let (tx, jg) = match ls.listener_type {
          ListenerType::HTTP => {
            network::http::start_listener(addr, ls.max_connections, sender)
          },
          ListenerType::HTTPS => {
            network::tls::start_listener(addr, ls.max_connections, None, sender)
          },
          _ => unimplemented!()
        };
        let l =  Listener::new(tag.clone(), ls.listener_type, ls.address.clone(), ls.port, tx, receiver);
        listeners.insert(tag.clone(), l);
        jh_opt = Some(jg);
      } else {
        error!("could not parse address: {}", address);
      }
    };

    command::start(config.command_socket, listeners);
    if let Some(jh) = jh_opt {
      let _ = jh.join();
      info!("good bye");
    }
  } else {
    println!("could not load configuration, stopping");
  }
}

<|endoftext|>