<commit_before>use syntax::ast::*;
use rustc::lint::*;
use rustc::middle::ty;
use std::iter;
use std::borrow::Cow;

use utils::{snippet, span_lint, match_path, match_type, walk_ptrs_ty_depth};
use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH};

use self::SelfKind::*;
use self::OutType::*;

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

declare_lint!(pub OPTION_UNWRAP_USED, Allow,
              "using `Option.unwrap()`, which should at least get a better message using `expect()`");
declare_lint!(pub RESULT_UNWRAP_USED, Allow,
              "using `Result.unwrap()`, which might be better handled");
declare_lint!(pub STR_TO_STRING, Warn,
              "using `to_string()` on a str, which should be `to_owned()`");
declare_lint!(pub STRING_TO_STRING, Warn,
              "calling `String.to_string()` which is a no-op");
declare_lint!(pub SHOULD_IMPLEMENT_TRAIT, Warn,
              "defining a method that should be implementing a std trait");
declare_lint!(pub WRONG_SELF_CONVENTION, Warn,
              "defining a method named with an established prefix (like \"into_\") that takes \
               `self` with the wrong convention");

impl LintPass for MethodsPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING,
                    SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprMethodCall(ref ident, _, ref args) = expr.node {
            let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0]));
            if ident.node.name == "unwrap" {
                if match_type(cx, obj_ty, &OPTION_PATH) {
                    span_lint(cx, OPTION_UNWRAP_USED, expr.span,
                              "used unwrap() on an Option value. If you don't want \
                               to handle the None case gracefully, consider using \
                               expect() to provide a better panic message");
                } else if match_type(cx, obj_ty, &RESULT_PATH) {
                    span_lint(cx, RESULT_UNWRAP_USED, expr.span,
                              "used unwrap() on a Result value. Graceful handling \
                               of Err values is preferred");
                }
            }
            else if ident.node.name == "to_string" {
                if obj_ty.sty == ty::TyStr {
                    let mut arg_str = snippet(cx, args[0].span, "_");
                    if ptr_depth > 1 {
                        arg_str = Cow::Owned(format!(
                            "({}{})",
                            iter::repeat('*').take(ptr_depth - 1).collect::<String>(),
                            arg_str));
                    }
                    span_lint(cx, STR_TO_STRING, expr.span, &format!(
                        "`{}.to_owned()` is faster", arg_str));
                } else if match_type(cx, obj_ty, &STRING_PATH) {
                    span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op; use \
                                                                `clone()` to make a copy");
                }
            }
        }
    }

    fn check_item(&mut self, cx: &Context, item: &Item) {
        if let ItemImpl(_, _, _, None, ref ty, ref items) = item.node {
            for implitem in items {
                let name = implitem.ident.name;
                if let MethodImplItem(ref sig, _) = implitem.node {
                    // check missing trait implementations
                    for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS {
                        if_let_chain! {
                            [
                                name == method_name,
                                sig.decl.inputs.len() == n_args,
                                out_type.matches(&sig.decl.output),
                                self_kind.matches(&sig.explicit_self.node, false)
                            ], {
                                span_lint(cx, SHOULD_IMPLEMENT_TRAIT, implitem.span, &format!(
                                    "defining a method called `{}` on this type; consider implementing \
                                     the `{}` trait or choosing a less ambiguous name", name, trait_name));
                            }
                        }
                    }
                    // check conventions w.r.t. conversion method names and predicates
                    let is_copy = is_copy(cx, &ty, &item);
                    for &(prefix, self_kinds) in &CONVENTIONS {
                        if name.as_str().starts_with(prefix) &&
                                !self_kinds.iter().any(|k| k.matches(&sig.explicit_self.node, is_copy)) {
                            span_lint(cx, WRONG_SELF_CONVENTION, sig.explicit_self.span, &format!(
                                "methods called `{}*` usually take {}; consider choosing a less \
                                 ambiguous name", prefix,
                                &self_kinds.iter().map(|k| k.description()).collect::<Vec<_>>().join(" or ")));
                        }
                    }
                }
            }
        }
    }
}

const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [
    ("into_", &[ValueSelf]),
    ("to_",   &[RefSelf]),
    ("as_",   &[RefSelf]),
    ("is_",   &[RefSelf, NoSelf]),
    ("from_", &[NoSelf]),
];

const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [
    ("add",        2, ValueSelf,  AnyType,  "std::ops::Add`"),
    ("sub",        2, ValueSelf,  AnyType,  "std::ops::Sub"),
    ("mul",        2, ValueSelf,  AnyType,  "std::ops::Mul"),
    ("div",        2, ValueSelf,  AnyType,  "std::ops::Div"),
    ("rem",        2, ValueSelf,  AnyType,  "std::ops::Rem"),
    ("shl",        2, ValueSelf,  AnyType,  "std::ops::Shl"),
    ("shr",        2, ValueSelf,  AnyType,  "std::ops::Shr"),
    ("bitand",     2, ValueSelf,  AnyType,  "std::ops::BitAnd"),
    ("bitor",      2, ValueSelf,  AnyType,  "std::ops::BitOr"),
    ("bitxor",     2, ValueSelf,  AnyType,  "std::ops::BitXor"),
    ("neg",        1, ValueSelf,  AnyType,  "std::ops::Neg"),
    ("not",        1, ValueSelf,  AnyType,  "std::ops::Not"),
    ("drop",       1, RefMutSelf, UnitType, "std::ops::Drop"),
    ("index",      2, RefSelf,    RefType,  "std::ops::Index"),
    ("index_mut",  2, RefMutSelf, RefType,  "std::ops::IndexMut"),
    ("deref",      1, RefSelf,    RefType,  "std::ops::Deref"),
    ("deref_mut",  1, RefMutSelf, RefType,  "std::ops::DerefMut"),
    ("clone",      1, RefSelf,    AnyType,  "std::clone::Clone"),
    ("borrow",     1, RefSelf,    RefType,  "std::borrow::Borrow"),
    ("borrow_mut", 1, RefMutSelf, RefType,  "std::borrow::BorrowMut"),
    ("as_ref",     1, RefSelf,    RefType,  "std::convert::AsRef"),
    ("as_mut",     1, RefMutSelf, RefType,  "std::convert::AsMut"),
    ("eq",         2, RefSelf,    BoolType, "std::cmp::PartialEq"),
    ("cmp",        2, RefSelf,    AnyType,  "std::cmp::Ord"),
    ("default",    0, NoSelf,     AnyType,  "std::default::Default"),
    ("hash",       2, RefSelf,    UnitType, "std::hash::Hash"),
    ("next",       1, RefMutSelf, AnyType,  "std::iter::Iterator"),
    ("into_iter",  1, ValueSelf,  AnyType,  "std::iter::IntoIterator"),
    ("from_iter",  1, NoSelf,     AnyType,  "std::iter::FromIterator"),
    ("from_str",   1, NoSelf,     AnyType,  "std::str::FromStr"),
];

#[derive(Clone, Copy)]
enum SelfKind {
    ValueSelf,
    RefSelf,
    RefMutSelf,
    NoSelf,
}

impl SelfKind {
    fn matches(&self, slf: &ExplicitSelf_, allow_value_for_ref: bool) -> bool {
        match (self, slf) {
            (&ValueSelf, &SelfValue(_)) => true,
            (&RefSelf, &SelfRegion(_, Mutability::MutImmutable, _)) => true,
            (&RefMutSelf, &SelfRegion(_, Mutability::MutMutable, _)) => true,
            (&RefSelf, &SelfValue(_)) => allow_value_for_ref,
            (&RefMutSelf, &SelfValue(_)) => allow_value_for_ref,
            (&NoSelf, &SelfStatic) => true,
            (_, &SelfExplicit(ref ty, _)) => self.matches_explicit_type(ty, allow_value_for_ref),
            _ => false
        }
    }

    fn matches_explicit_type(&self, ty: &Ty, allow_value_for_ref: bool) -> bool {
        match (self, &ty.node) {
            (&ValueSelf, &TyPath(..)) => true,
            (&RefSelf, &TyRptr(_, MutTy { mutbl: Mutability::MutImmutable, .. })) => true,
            (&RefMutSelf, &TyRptr(_, MutTy { mutbl: Mutability::MutMutable, .. })) => true,
            (&RefSelf, &TyPath(..)) => allow_value_for_ref,
            (&RefMutSelf, &TyPath(..)) => allow_value_for_ref,
            _ => false
        }
    }

    fn description(&self) -> &'static str {
        match *self {
            ValueSelf => "self by value",
            RefSelf => "self by reference",
            RefMutSelf => "self by mutable reference",
            NoSelf => "no self",
        }
    }
}

#[derive(Clone, Copy)]
enum OutType {
    UnitType,
    BoolType,
    AnyType,
    RefType,
}

impl OutType {
    fn matches(&self, ty: &FunctionRetTy) -> bool {
        match (self, ty) {
            (&UnitType, &DefaultReturn(_)) => true,
            (&UnitType, &Return(ref ty)) if ty.node == TyTup(vec![]) => true,
            (&BoolType, &Return(ref ty)) if is_bool(ty) => true,
            (&AnyType, &Return(ref ty)) if ty.node != TyTup(vec![])  => true,
            (&RefType, &Return(ref ty)) => {
                if let TyRptr(_, _) = ty.node { true } else { false }
            }
            _ => false
        }
    }
}

fn is_bool(ty: &Ty) -> bool {
    if let TyPath(None, ref p) = ty.node {
        if match_path(p, &["bool"]) {
            return true;
        }
    }
    false
}

fn is_copy(cx: &Context, ast_ty: &Ty, item: &Item) -> bool {
    match cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) {
        None => false,
        Some(ty) => {
            let env = ty::ParameterEnvironment::for_item(cx.tcx, item.id);
            !ty.moves_by_default(&env, ast_ty.span)
        }
    }
}
<commit_msg>Fix ICE<commit_after>use syntax::ast::*;
use rustc::lint::*;
use rustc::middle::ty;
use rustc::middle::subst::Subst;
use std::iter;
use std::borrow::Cow;

use utils::{snippet, span_lint, match_path, match_type, walk_ptrs_ty_depth};
use utils::{OPTION_PATH, RESULT_PATH, STRING_PATH};

use self::SelfKind::*;
use self::OutType::*;

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

declare_lint!(pub OPTION_UNWRAP_USED, Allow,
              "using `Option.unwrap()`, which should at least get a better message using `expect()`");
declare_lint!(pub RESULT_UNWRAP_USED, Allow,
              "using `Result.unwrap()`, which might be better handled");
declare_lint!(pub STR_TO_STRING, Warn,
              "using `to_string()` on a str, which should be `to_owned()`");
declare_lint!(pub STRING_TO_STRING, Warn,
              "calling `String.to_string()` which is a no-op");
declare_lint!(pub SHOULD_IMPLEMENT_TRAIT, Warn,
              "defining a method that should be implementing a std trait");
declare_lint!(pub WRONG_SELF_CONVENTION, Warn,
              "defining a method named with an established prefix (like \"into_\") that takes \
               `self` with the wrong convention");

impl LintPass for MethodsPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, STR_TO_STRING, STRING_TO_STRING,
                    SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprMethodCall(ref ident, _, ref args) = expr.node {
            let (obj_ty, ptr_depth) = walk_ptrs_ty_depth(cx.tcx.expr_ty(&args[0]));
            if ident.node.name == "unwrap" {
                if match_type(cx, obj_ty, &OPTION_PATH) {
                    span_lint(cx, OPTION_UNWRAP_USED, expr.span,
                              "used unwrap() on an Option value. If you don't want \
                               to handle the None case gracefully, consider using \
                               expect() to provide a better panic message");
                } else if match_type(cx, obj_ty, &RESULT_PATH) {
                    span_lint(cx, RESULT_UNWRAP_USED, expr.span,
                              "used unwrap() on a Result value. Graceful handling \
                               of Err values is preferred");
                }
            }
            else if ident.node.name == "to_string" {
                if obj_ty.sty == ty::TyStr {
                    let mut arg_str = snippet(cx, args[0].span, "_");
                    if ptr_depth > 1 {
                        arg_str = Cow::Owned(format!(
                            "({}{})",
                            iter::repeat('*').take(ptr_depth - 1).collect::<String>(),
                            arg_str));
                    }
                    span_lint(cx, STR_TO_STRING, expr.span, &format!(
                        "`{}.to_owned()` is faster", arg_str));
                } else if match_type(cx, obj_ty, &STRING_PATH) {
                    span_lint(cx, STRING_TO_STRING, expr.span, "`String.to_string()` is a no-op; use \
                                                                `clone()` to make a copy");
                }
            }
        }
    }

    fn check_item(&mut self, cx: &Context, item: &Item) {
        if let ItemImpl(_, _, _, None, ref ty, ref items) = item.node {
            for implitem in items {
                let name = implitem.ident.name;
                if let MethodImplItem(ref sig, _) = implitem.node {
                    // check missing trait implementations
                    for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS {
                        if_let_chain! {
                            [
                                name == method_name,
                                sig.decl.inputs.len() == n_args,
                                out_type.matches(&sig.decl.output),
                                self_kind.matches(&sig.explicit_self.node, false)
                            ], {
                                span_lint(cx, SHOULD_IMPLEMENT_TRAIT, implitem.span, &format!(
                                    "defining a method called `{}` on this type; consider implementing \
                                     the `{}` trait or choosing a less ambiguous name", name, trait_name));
                            }
                        }
                    }
                    // check conventions w.r.t. conversion method names and predicates
                    let is_copy = is_copy(cx, &ty, &item);
                    for &(prefix, self_kinds) in &CONVENTIONS {
                        if name.as_str().starts_with(prefix) &&
                                !self_kinds.iter().any(|k| k.matches(&sig.explicit_self.node, is_copy)) {
                            span_lint(cx, WRONG_SELF_CONVENTION, sig.explicit_self.span, &format!(
                                "methods called `{}*` usually take {}; consider choosing a less \
                                 ambiguous name", prefix,
                                &self_kinds.iter().map(|k| k.description()).collect::<Vec<_>>().join(" or ")));
                        }
                    }
                }
            }
        }
    }
}

const CONVENTIONS: [(&'static str, &'static [SelfKind]); 5] = [
    ("into_", &[ValueSelf]),
    ("to_",   &[RefSelf]),
    ("as_",   &[RefSelf]),
    ("is_",   &[RefSelf, NoSelf]),
    ("from_", &[NoSelf]),
];

const TRAIT_METHODS: [(&'static str, usize, SelfKind, OutType, &'static str); 30] = [
    ("add",        2, ValueSelf,  AnyType,  "std::ops::Add`"),
    ("sub",        2, ValueSelf,  AnyType,  "std::ops::Sub"),
    ("mul",        2, ValueSelf,  AnyType,  "std::ops::Mul"),
    ("div",        2, ValueSelf,  AnyType,  "std::ops::Div"),
    ("rem",        2, ValueSelf,  AnyType,  "std::ops::Rem"),
    ("shl",        2, ValueSelf,  AnyType,  "std::ops::Shl"),
    ("shr",        2, ValueSelf,  AnyType,  "std::ops::Shr"),
    ("bitand",     2, ValueSelf,  AnyType,  "std::ops::BitAnd"),
    ("bitor",      2, ValueSelf,  AnyType,  "std::ops::BitOr"),
    ("bitxor",     2, ValueSelf,  AnyType,  "std::ops::BitXor"),
    ("neg",        1, ValueSelf,  AnyType,  "std::ops::Neg"),
    ("not",        1, ValueSelf,  AnyType,  "std::ops::Not"),
    ("drop",       1, RefMutSelf, UnitType, "std::ops::Drop"),
    ("index",      2, RefSelf,    RefType,  "std::ops::Index"),
    ("index_mut",  2, RefMutSelf, RefType,  "std::ops::IndexMut"),
    ("deref",      1, RefSelf,    RefType,  "std::ops::Deref"),
    ("deref_mut",  1, RefMutSelf, RefType,  "std::ops::DerefMut"),
    ("clone",      1, RefSelf,    AnyType,  "std::clone::Clone"),
    ("borrow",     1, RefSelf,    RefType,  "std::borrow::Borrow"),
    ("borrow_mut", 1, RefMutSelf, RefType,  "std::borrow::BorrowMut"),
    ("as_ref",     1, RefSelf,    RefType,  "std::convert::AsRef"),
    ("as_mut",     1, RefMutSelf, RefType,  "std::convert::AsMut"),
    ("eq",         2, RefSelf,    BoolType, "std::cmp::PartialEq"),
    ("cmp",        2, RefSelf,    AnyType,  "std::cmp::Ord"),
    ("default",    0, NoSelf,     AnyType,  "std::default::Default"),
    ("hash",       2, RefSelf,    UnitType, "std::hash::Hash"),
    ("next",       1, RefMutSelf, AnyType,  "std::iter::Iterator"),
    ("into_iter",  1, ValueSelf,  AnyType,  "std::iter::IntoIterator"),
    ("from_iter",  1, NoSelf,     AnyType,  "std::iter::FromIterator"),
    ("from_str",   1, NoSelf,     AnyType,  "std::str::FromStr"),
];

#[derive(Clone, Copy)]
enum SelfKind {
    ValueSelf,
    RefSelf,
    RefMutSelf,
    NoSelf,
}

impl SelfKind {
    fn matches(&self, slf: &ExplicitSelf_, allow_value_for_ref: bool) -> bool {
        match (self, slf) {
            (&ValueSelf, &SelfValue(_)) => true,
            (&RefSelf, &SelfRegion(_, Mutability::MutImmutable, _)) => true,
            (&RefMutSelf, &SelfRegion(_, Mutability::MutMutable, _)) => true,
            (&RefSelf, &SelfValue(_)) => allow_value_for_ref,
            (&RefMutSelf, &SelfValue(_)) => allow_value_for_ref,
            (&NoSelf, &SelfStatic) => true,
            (_, &SelfExplicit(ref ty, _)) => self.matches_explicit_type(ty, allow_value_for_ref),
            _ => false
        }
    }

    fn matches_explicit_type(&self, ty: &Ty, allow_value_for_ref: bool) -> bool {
        match (self, &ty.node) {
            (&ValueSelf, &TyPath(..)) => true,
            (&RefSelf, &TyRptr(_, MutTy { mutbl: Mutability::MutImmutable, .. })) => true,
            (&RefMutSelf, &TyRptr(_, MutTy { mutbl: Mutability::MutMutable, .. })) => true,
            (&RefSelf, &TyPath(..)) => allow_value_for_ref,
            (&RefMutSelf, &TyPath(..)) => allow_value_for_ref,
            _ => false
        }
    }

    fn description(&self) -> &'static str {
        match *self {
            ValueSelf => "self by value",
            RefSelf => "self by reference",
            RefMutSelf => "self by mutable reference",
            NoSelf => "no self",
        }
    }
}

#[derive(Clone, Copy)]
enum OutType {
    UnitType,
    BoolType,
    AnyType,
    RefType,
}

impl OutType {
    fn matches(&self, ty: &FunctionRetTy) -> bool {
        match (self, ty) {
            (&UnitType, &DefaultReturn(_)) => true,
            (&UnitType, &Return(ref ty)) if ty.node == TyTup(vec![]) => true,
            (&BoolType, &Return(ref ty)) if is_bool(ty) => true,
            (&AnyType, &Return(ref ty)) if ty.node != TyTup(vec![])  => true,
            (&RefType, &Return(ref ty)) => {
                if let TyRptr(_, _) = ty.node { true } else { false }
            }
            _ => false
        }
    }
}

fn is_bool(ty: &Ty) -> bool {
    if let TyPath(None, ref p) = ty.node {
        if match_path(p, &["bool"]) {
            return true;
        }
    }
    false
}

fn is_copy(cx: &Context, ast_ty: &Ty, item: &Item) -> bool {
    match cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) {
        None => false,
        Some(ty) => {
            let env = ty::ParameterEnvironment::for_item(cx.tcx, item.id);
            !ty.subst(cx.tcx, &env.free_substs).moves_by_default(&env, ast_ty.span)
        }
    }
}
<|endoftext|>


<commit_before>//! Defines the most basic types and constants like the pieces,
//! colors, squares, files, and ranks.
//!
//! This module also defines few simple functions.

use std::fmt;

/// `WHITE` or `BLACK`.
pub type Color = usize;

pub const WHITE: Color = 0;
pub const BLACK: Color = 1;

/// `KING`, `QUEEN`, `ROOK`, `BISHOP`, `KINGHT`, `PAWN` or `NO_PIECE`.
pub type PieceType = usize;

pub const KING: PieceType = 0;
pub const QUEEN: PieceType = 1;
pub const ROOK: PieceType = 2;
pub const BISHOP: PieceType = 3;
pub const KNIGHT: PieceType = 4;
pub const PAWN: PieceType = 5;
pub const NO_PIECE: PieceType = 6;

/// From 0 to 7 (0 is rank 1, 7 is rank 8).
pub type Rank = usize;

pub const RANK_1: Rank = 0;
pub const RANK_2: Rank = 1;
pub const RANK_3: Rank = 2;
pub const RANK_4: Rank = 3;
pub const RANK_5: Rank = 4;
pub const RANK_6: Rank = 5;
pub const RANK_7: Rank = 6;
pub const RANK_8: Rank = 7;

/// From 0 to 7 (0 is file A, 7 is file H).
pub type File = usize;

pub const FILE_A: File = 0;
pub const FILE_B: File = 1;
pub const FILE_C: File = 2;
pub const FILE_D: File = 3;
pub const FILE_E: File = 4;
pub const FILE_F: File = 5;
pub const FILE_G: File = 6;
pub const FILE_H: File = 7;

/// From 0 to 63 (0 is A1, 63 is H8).
pub type Square = usize;

pub const A1: Square = 0 + 0 * 8;
pub const B1: Square = 1 + 0 * 8;
pub const C1: Square = 2 + 0 * 8;
pub const D1: Square = 3 + 0 * 8;
pub const E1: Square = 4 + 0 * 8;
pub const F1: Square = 5 + 0 * 8;
pub const G1: Square = 6 + 0 * 8;
pub const H1: Square = 7 + 0 * 8;
pub const A2: Square = 0 + 1 * 8;
pub const B2: Square = 1 + 1 * 8;
pub const C2: Square = 2 + 1 * 8;
pub const D2: Square = 3 + 1 * 8;
pub const E2: Square = 4 + 1 * 8;
pub const F2: Square = 5 + 1 * 8;
pub const G2: Square = 6 + 1 * 8;
pub const H2: Square = 7 + 1 * 8;
pub const A3: Square = 0 + 2 * 8;
pub const B3: Square = 1 + 2 * 8;
pub const C3: Square = 2 + 2 * 8;
pub const D3: Square = 3 + 2 * 8;
pub const E3: Square = 4 + 2 * 8;
pub const F3: Square = 5 + 2 * 8;
pub const G3: Square = 6 + 2 * 8;
pub const H3: Square = 7 + 2 * 8;
pub const A4: Square = 0 + 3 * 8;
pub const B4: Square = 1 + 3 * 8;
pub const C4: Square = 2 + 3 * 8;
pub const D4: Square = 3 + 3 * 8;
pub const E4: Square = 4 + 3 * 8;
pub const F4: Square = 5 + 3 * 8;
pub const G4: Square = 6 + 3 * 8;
pub const H4: Square = 7 + 3 * 8;
pub const A5: Square = 0 + 4 * 8;
pub const B5: Square = 1 + 4 * 8;
pub const C5: Square = 2 + 4 * 8;
pub const D5: Square = 3 + 4 * 8;
pub const E5: Square = 4 + 4 * 8;
pub const F5: Square = 5 + 4 * 8;
pub const G5: Square = 6 + 4 * 8;
pub const H5: Square = 7 + 4 * 8;
pub const A6: Square = 0 + 5 * 8;
pub const B6: Square = 1 + 5 * 8;
pub const C6: Square = 2 + 5 * 8;
pub const D6: Square = 3 + 5 * 8;
pub const E6: Square = 4 + 5 * 8;
pub const F6: Square = 5 + 5 * 8;
pub const G6: Square = 6 + 5 * 8;
pub const H6: Square = 7 + 5 * 8;
pub const A7: Square = 0 + 6 * 8;
pub const B7: Square = 1 + 6 * 8;
pub const C7: Square = 2 + 6 * 8;
pub const D7: Square = 3 + 6 * 8;
pub const E7: Square = 4 + 6 * 8;
pub const F7: Square = 5 + 6 * 8;
pub const G7: Square = 6 + 6 * 8;
pub const H7: Square = 7 + 6 * 8;
pub const A8: Square = 0 + 7 * 8;
pub const B8: Square = 1 + 7 * 8;
pub const C8: Square = 2 + 7 * 8;
pub const D8: Square = 3 + 7 * 8;
pub const E8: Square = 4 + 7 * 8;
pub const F8: Square = 5 + 7 * 8;
pub const G8: Square = 6 + 7 * 8;
pub const H8: Square = 7 + 7 * 8;

/// A set of squares on the chessboard.
///
/// `u64` bit-sets called *bitboards* can be used to represent a set
/// of squares on the chessboard. For example, the set of squares that
/// are occupied by white rooks in the beginning of the game is: `1 <<
/// A1 | 1 << H1`. `0` represents the empty set, `0xffffffffffffffff`
/// represents the set of all 64 squares on the board.
pub type Bitboard = u64;

/// Evaluation value in centipawns.
///
/// Positive values mean that the position is favorable for the side
/// to move. Negative values mean the position is favorable for the
/// other side (not to move). A value of `0` means that the chances
/// are equal. For example: a value of `100` might mean that the side
/// to move is a pawn ahead.
///
/// # Constants:
///
/// * `VALUE_UNKNOWN` has the special meaning of "unknown value".
///
/// * `VALUE_MAX` designates a checkmate (a win).
///
/// * `VALUE_MIN` designates a checkmate (a loss).
///
/// * Values bigger than `VALUE_EVAL_MAX` designate a win by
///   inevitable checkmate.
///
/// * Values smaller than `VALUE_EVAL_MIN` designate a loss by
///   inevitable checkmate.
pub type Value = i16;

/// Equals `-32768` and has the special meaning of "unknown value".
pub const VALUE_UNKNOWN: Value = VALUE_MIN - 1;

/// Equals `32767`, and designates a checkmate (a win).
pub const VALUE_MAX: Value = ::std::i16::MAX;

/// Equals `-32767`, and designates a checkmate (a loss).
pub const VALUE_MIN: Value = -VALUE_MAX;

/// Equals `29999`, values bigger than that designate a win by
/// inevitable checkmate.
pub const VALUE_EVAL_MAX: Value = 29999;

/// Equals `-29999`, values smaller than that designate a loss by
/// inevitable checkmate.
pub const VALUE_EVAL_MIN: Value = -VALUE_EVAL_MAX;

/// `QUEENSIDE` or `KINGSIDE`.
pub type CastlingSide = usize; // 0 or 1

pub const QUEENSIDE: CastlingSide = 0;
pub const KINGSIDE: CastlingSide = 1;

/// Describes how pieces are placed on the board.
#[derive(Clone, Copy, Debug)]
pub struct PiecesPlacement {
    /// An array of occupation bitboards indexed by piece type.  For
    /// example, `piece_placement.piece_type[PAWN]` gives the set of
    /// all pawns on the board (white and black).
    pub piece_type: [Bitboard; 6],

    /// An array of occupation bitboards indexed by color.  For
    /// example, `piece_placement.color[WHITE]` gives the set of all
    /// white pieces and pawns on the board.
    pub color: [Bitboard; 2],
}

impl fmt::Display for PiecesPlacement {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = String::new();
        for rank in (0..8).rev() {
            s.push('\n');
            for file in 0..8 {
                let square = square(file, rank);
                let bb = 1 << square;
                let piece = match bb {
                    x if x & self.piece_type[KING] != 0 => 'k',
                    x if x & self.piece_type[QUEEN] != 0 => 'q',
                    x if x & self.piece_type[ROOK] != 0 => 'r',
                    x if x & self.piece_type[BISHOP] != 0 => 'b',
                    x if x & self.piece_type[KNIGHT] != 0 => 'n',
                    x if x & self.piece_type[PAWN] != 0 => 'p',
                    _ => '.',
                };
                if bb & self.color[WHITE] != 0 {
                    s.push(piece.to_uppercase().next().unwrap());
                } else {
                    s.push(piece);
                }
            }
        }
        writeln!(f, "{}", s)
    }
}

/// Holds information about which player can castle on which side.
///
/// The castling rights are held in a `usize` value. The lowest 4 bits
/// of the value contain the whole needed information. It is laid out
/// in the following way:
///
/// ```text
///  usize                    3   2   1   0
///  +----------------------+---+---+---+---+
///  |                      |   |   |   |   |
///  |    Unused (zeros)    |Castling flags |
///  |                      |   |   |   |   |
///  +----------------------+---+---+---+---+
///
///  bit 0 -- if set, white can castle on queen-side;
///  bit 1 -- if set, white can castle on king-side;
///  bit 2 -- if set, black can castle on queen-side;
///  bit 3 -- if set, black can castle on king-side.
/// ```
#[derive(Clone, Copy, Debug)]
pub struct CastlingRights(usize);

impl CastlingRights {
    /// Creates a new instance.
    ///
    /// The least significant 4 bits of `value` are used as a raw
    /// value for the new instance.
    #[inline(always)]
    pub fn new(value: usize) -> CastlingRights {
        CastlingRights(value & 0b1111)
    }

    /// Returns the contained raw value (between 0 and 15).
    #[inline(always)]
    pub fn value(&self) -> usize {
        self.0
    }

    /// Grants a given player the right to castle on a given side.
    ///
    /// This method returns `true` if the player did not have the
    /// right to castle on the given side before this method was
    /// called, and `false` otherwise.
    pub fn grant(&mut self, player: Color, side: CastlingSide) -> bool {
        assert!(player <= 1);
        assert!(side <= 1);
        let rights_before = self.0;
        let granted = 1 << (player << 1) << side;
        self.0 |= granted;

        granted & !rights_before != 0
    }

    /// Updates the castling rights after played move.
    ///
    /// `orig_square` and `dest_square` describe the played move.
    #[inline(always)]
    pub fn update(&mut self, orig_square: Square, dest_square: Square) {
        debug_assert!(orig_square <= 63);
        debug_assert!(dest_square <= 63);
        const WQ: usize = (1 << (WHITE << 1) << QUEENSIDE);
        const WK: usize = (1 << (WHITE << 1) << KINGSIDE);
        const W: usize = WQ | WK;
        const BQ: usize = (1 << (BLACK << 1) << QUEENSIDE);
        const BK: usize = (1 << (BLACK << 1) << KINGSIDE);
        const B: usize = BQ | BK;

        // On each move, the value of `CASTLING_RELATION` for the
        // origin and destination squares should be AND-ed with the
        // castling rights value, to derive the updated castling
        // rights.
        const CASTLING_RELATION: [usize; 64] = [
            !WQ, !0,  !0,  !0,  !W,  !0,  !0,  !WK,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !BQ, !0,  !0,  !0,  !B,  !0,  !0,  !BK,
        ];
        self.0 &= CASTLING_RELATION[orig_square] & CASTLING_RELATION[dest_square];
    }

    /// Returns if a given player has the rights to castle on a given
    /// side.
    #[inline(always)]
    pub fn can_castle(&self, player: Color, side: CastlingSide) -> bool {
        debug_assert!(player <= 1);
        debug_assert!(side <= 1);
        (1 << (player << 1) << side) & self.0 != 0
    }
}

impl fmt::Display for CastlingRights {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut value = self.value();
        for s in ["Q", "K", "q", "k"].iter() {
            if value & 1 == 1 {
                try!(f.write_str(s));
            }
            value >>= 1;
        }
        Ok(())
    }
}

/// Returns the square on given file and rank.
#[inline]
pub fn square(file: File, rank: Rank) -> Square {
    debug_assert!(file < 8);
    debug_assert!(rank < 8);
    rank * 8 + file
}

/// Returns the rank of a given square.
#[inline(always)]
pub fn rank(square: Square) -> Rank {
    debug_assert!(square <= 63);
    square >> 3
}

/// Returns the file of a given square.
#[inline(always)]
pub fn file(square: Square) -> File {
    debug_assert!(square <= 63);
    square % 8
}
<commit_msg>fix doc<commit_after>//! Defines the most basic types and constants like the pieces,
//! colors, squares, files, and ranks.
//!
//! This module also defines few simple functions.

use std::fmt;

/// `WHITE` or `BLACK`.
pub type Color = usize;

pub const WHITE: Color = 0;
pub const BLACK: Color = 1;

/// `KING`, `QUEEN`, `ROOK`, `BISHOP`, `KINGHT`, `PAWN` or `NO_PIECE`.
pub type PieceType = usize;

pub const KING: PieceType = 0;
pub const QUEEN: PieceType = 1;
pub const ROOK: PieceType = 2;
pub const BISHOP: PieceType = 3;
pub const KNIGHT: PieceType = 4;
pub const PAWN: PieceType = 5;
pub const NO_PIECE: PieceType = 6;

/// From 0 to 7 (0 is rank 1, 7 is rank 8).
pub type Rank = usize;

pub const RANK_1: Rank = 0;
pub const RANK_2: Rank = 1;
pub const RANK_3: Rank = 2;
pub const RANK_4: Rank = 3;
pub const RANK_5: Rank = 4;
pub const RANK_6: Rank = 5;
pub const RANK_7: Rank = 6;
pub const RANK_8: Rank = 7;

/// From 0 to 7 (0 is file A, 7 is file H).
pub type File = usize;

pub const FILE_A: File = 0;
pub const FILE_B: File = 1;
pub const FILE_C: File = 2;
pub const FILE_D: File = 3;
pub const FILE_E: File = 4;
pub const FILE_F: File = 5;
pub const FILE_G: File = 6;
pub const FILE_H: File = 7;

/// From 0 to 63 (0 is A1, 63 is H8).
pub type Square = usize;

pub const A1: Square = 0 + 0 * 8;
pub const B1: Square = 1 + 0 * 8;
pub const C1: Square = 2 + 0 * 8;
pub const D1: Square = 3 + 0 * 8;
pub const E1: Square = 4 + 0 * 8;
pub const F1: Square = 5 + 0 * 8;
pub const G1: Square = 6 + 0 * 8;
pub const H1: Square = 7 + 0 * 8;
pub const A2: Square = 0 + 1 * 8;
pub const B2: Square = 1 + 1 * 8;
pub const C2: Square = 2 + 1 * 8;
pub const D2: Square = 3 + 1 * 8;
pub const E2: Square = 4 + 1 * 8;
pub const F2: Square = 5 + 1 * 8;
pub const G2: Square = 6 + 1 * 8;
pub const H2: Square = 7 + 1 * 8;
pub const A3: Square = 0 + 2 * 8;
pub const B3: Square = 1 + 2 * 8;
pub const C3: Square = 2 + 2 * 8;
pub const D3: Square = 3 + 2 * 8;
pub const E3: Square = 4 + 2 * 8;
pub const F3: Square = 5 + 2 * 8;
pub const G3: Square = 6 + 2 * 8;
pub const H3: Square = 7 + 2 * 8;
pub const A4: Square = 0 + 3 * 8;
pub const B4: Square = 1 + 3 * 8;
pub const C4: Square = 2 + 3 * 8;
pub const D4: Square = 3 + 3 * 8;
pub const E4: Square = 4 + 3 * 8;
pub const F4: Square = 5 + 3 * 8;
pub const G4: Square = 6 + 3 * 8;
pub const H4: Square = 7 + 3 * 8;
pub const A5: Square = 0 + 4 * 8;
pub const B5: Square = 1 + 4 * 8;
pub const C5: Square = 2 + 4 * 8;
pub const D5: Square = 3 + 4 * 8;
pub const E5: Square = 4 + 4 * 8;
pub const F5: Square = 5 + 4 * 8;
pub const G5: Square = 6 + 4 * 8;
pub const H5: Square = 7 + 4 * 8;
pub const A6: Square = 0 + 5 * 8;
pub const B6: Square = 1 + 5 * 8;
pub const C6: Square = 2 + 5 * 8;
pub const D6: Square = 3 + 5 * 8;
pub const E6: Square = 4 + 5 * 8;
pub const F6: Square = 5 + 5 * 8;
pub const G6: Square = 6 + 5 * 8;
pub const H6: Square = 7 + 5 * 8;
pub const A7: Square = 0 + 6 * 8;
pub const B7: Square = 1 + 6 * 8;
pub const C7: Square = 2 + 6 * 8;
pub const D7: Square = 3 + 6 * 8;
pub const E7: Square = 4 + 6 * 8;
pub const F7: Square = 5 + 6 * 8;
pub const G7: Square = 6 + 6 * 8;
pub const H7: Square = 7 + 6 * 8;
pub const A8: Square = 0 + 7 * 8;
pub const B8: Square = 1 + 7 * 8;
pub const C8: Square = 2 + 7 * 8;
pub const D8: Square = 3 + 7 * 8;
pub const E8: Square = 4 + 7 * 8;
pub const F8: Square = 5 + 7 * 8;
pub const G8: Square = 6 + 7 * 8;
pub const H8: Square = 7 + 7 * 8;

/// A set of squares on the chessboard.
///
/// `u64` bit-sets called *bitboards* can be used to represent a set
/// of squares on the chessboard. For example, the set of squares that
/// are occupied by white rooks in the beginning of the game is: `1 <<
/// A1 | 1 << H1`. `0` represents the empty set, `0xffffffffffffffff`
/// represents the set of all 64 squares on the board.
pub type Bitboard = u64;

/// Evaluation value in centipawns.
///
/// Positive values mean that the position is favorable for the side
/// to move. Negative values mean the position is favorable for the
/// other side (not to move). A value of `0` means that the chances
/// are equal. For example: a value of `100` might mean that the side
/// to move is a pawn ahead.
///
/// # Constants:
///
/// * `VALUE_UNKNOWN` has the special meaning of "unknown value".
///
/// * `VALUE_MAX` designates a checkmate (a win).
///
/// * `VALUE_MIN` designates a checkmate (a loss).
///
/// * Values bigger than `VALUE_EVAL_MAX` designate a win by
///   inevitable checkmate.
///
/// * Values smaller than `VALUE_EVAL_MIN` designate a loss by
///   inevitable checkmate.
pub type Value = i16;

/// Equals `-32768` and has the special meaning of "unknown value".
pub const VALUE_UNKNOWN: Value = VALUE_MIN - 1;

/// Equals `32767` and designates a checkmate (a win).
pub const VALUE_MAX: Value = ::std::i16::MAX;

/// Equals `-32767` and designates a checkmate (a loss).
pub const VALUE_MIN: Value = -VALUE_MAX;

/// Equals `29999`, values bigger than that designate a win by
/// inevitable checkmate.
pub const VALUE_EVAL_MAX: Value = 29999;

/// Equals `-29999`, values smaller than that designate a loss by
/// inevitable checkmate.
pub const VALUE_EVAL_MIN: Value = -VALUE_EVAL_MAX;

/// `QUEENSIDE` or `KINGSIDE`.
pub type CastlingSide = usize; // 0 or 1

pub const QUEENSIDE: CastlingSide = 0;
pub const KINGSIDE: CastlingSide = 1;

/// Describes how pieces are placed on the board.
#[derive(Clone, Copy, Debug)]
pub struct PiecesPlacement {
    /// An array of occupation bitboards indexed by piece type.  For
    /// example, `piece_placement.piece_type[PAWN]` gives the set of
    /// all pawns on the board (white and black).
    pub piece_type: [Bitboard; 6],

    /// An array of occupation bitboards indexed by color.  For
    /// example, `piece_placement.color[WHITE]` gives the set of all
    /// white pieces and pawns on the board.
    pub color: [Bitboard; 2],
}

impl fmt::Display for PiecesPlacement {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = String::new();
        for rank in (0..8).rev() {
            s.push('\n');
            for file in 0..8 {
                let square = square(file, rank);
                let bb = 1 << square;
                let piece = match bb {
                    x if x & self.piece_type[KING] != 0 => 'k',
                    x if x & self.piece_type[QUEEN] != 0 => 'q',
                    x if x & self.piece_type[ROOK] != 0 => 'r',
                    x if x & self.piece_type[BISHOP] != 0 => 'b',
                    x if x & self.piece_type[KNIGHT] != 0 => 'n',
                    x if x & self.piece_type[PAWN] != 0 => 'p',
                    _ => '.',
                };
                if bb & self.color[WHITE] != 0 {
                    s.push(piece.to_uppercase().next().unwrap());
                } else {
                    s.push(piece);
                }
            }
        }
        writeln!(f, "{}", s)
    }
}

/// Holds information about which player can castle on which side.
///
/// The castling rights are held in a `usize` value. The lowest 4 bits
/// of the value contain the whole needed information. It is laid out
/// in the following way:
///
/// ```text
///  usize                    3   2   1   0
///  +----------------------+---+---+---+---+
///  |                      |   |   |   |   |
///  |    Unused (zeros)    |Castling flags |
///  |                      |   |   |   |   |
///  +----------------------+---+---+---+---+
///
///  bit 0 -- if set, white can castle on queen-side;
///  bit 1 -- if set, white can castle on king-side;
///  bit 2 -- if set, black can castle on queen-side;
///  bit 3 -- if set, black can castle on king-side.
/// ```
#[derive(Clone, Copy, Debug)]
pub struct CastlingRights(usize);

impl CastlingRights {
    /// Creates a new instance.
    ///
    /// The least significant 4 bits of `value` are used as a raw
    /// value for the new instance.
    #[inline(always)]
    pub fn new(value: usize) -> CastlingRights {
        CastlingRights(value & 0b1111)
    }

    /// Returns the contained raw value (between 0 and 15).
    #[inline(always)]
    pub fn value(&self) -> usize {
        self.0
    }

    /// Grants a given player the right to castle on a given side.
    ///
    /// This method returns `true` if the player did not have the
    /// right to castle on the given side before this method was
    /// called, and `false` otherwise.
    pub fn grant(&mut self, player: Color, side: CastlingSide) -> bool {
        assert!(player <= 1);
        assert!(side <= 1);
        let rights_before = self.0;
        let granted = 1 << (player << 1) << side;
        self.0 |= granted;

        granted & !rights_before != 0
    }

    /// Updates the castling rights after played move.
    ///
    /// `orig_square` and `dest_square` describe the played move.
    #[inline(always)]
    pub fn update(&mut self, orig_square: Square, dest_square: Square) {
        debug_assert!(orig_square <= 63);
        debug_assert!(dest_square <= 63);
        const WQ: usize = (1 << (WHITE << 1) << QUEENSIDE);
        const WK: usize = (1 << (WHITE << 1) << KINGSIDE);
        const W: usize = WQ | WK;
        const BQ: usize = (1 << (BLACK << 1) << QUEENSIDE);
        const BK: usize = (1 << (BLACK << 1) << KINGSIDE);
        const B: usize = BQ | BK;

        // On each move, the value of `CASTLING_RELATION` for the
        // origin and destination squares should be AND-ed with the
        // castling rights value, to derive the updated castling
        // rights.
        const CASTLING_RELATION: [usize; 64] = [
            !WQ, !0,  !0,  !0,  !W,  !0,  !0,  !WK,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !BQ, !0,  !0,  !0,  !B,  !0,  !0,  !BK,
        ];
        self.0 &= CASTLING_RELATION[orig_square] & CASTLING_RELATION[dest_square];
    }

    /// Returns if a given player has the rights to castle on a given
    /// side.
    #[inline(always)]
    pub fn can_castle(&self, player: Color, side: CastlingSide) -> bool {
        debug_assert!(player <= 1);
        debug_assert!(side <= 1);
        (1 << (player << 1) << side) & self.0 != 0
    }
}

impl fmt::Display for CastlingRights {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut value = self.value();
        for s in ["Q", "K", "q", "k"].iter() {
            if value & 1 == 1 {
                try!(f.write_str(s));
            }
            value >>= 1;
        }
        Ok(())
    }
}

/// Returns the square on given file and rank.
#[inline]
pub fn square(file: File, rank: Rank) -> Square {
    debug_assert!(file < 8);
    debug_assert!(rank < 8);
    rank * 8 + file
}

/// Returns the rank of a given square.
#[inline(always)]
pub fn rank(square: Square) -> Rank {
    debug_assert!(square <= 63);
    square >> 3
}

/// Returns the file of a given square.
#[inline(always)]
pub fn file(square: Square) -> File {
    debug_assert!(square <= 63);
    square % 8
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![deny(bare_trait_objects)]

mod common;
mod decoder;
mod muxer;
use crate::common::*;
use rav1e::prelude::*;

use std::io;
use std::io::Write;
use std::io::Read;
use std::path::Path;
use std::sync::Arc;
use crate::decoder::Decoder;
use crate::decoder::VideoDetails;
use crate::muxer::*;
use std::fs::File;
use std::io::BufWriter;

struct Source<D: Decoder> {
 limit: usize,
 count: usize,
 input: D,
 #[cfg(all(unix, feature = "signal-hook"))]
 exit_requested: Arc<std::sync::atomic::AtomicBool>,
}

impl<D: Decoder> Source<D> {
  fn read_frame<T: Pixel>(&mut self, ctx: &mut Context<T>, video_info: VideoDetails) {
    if self.limit != 0 && self.count == self.limit {
      ctx.flush();
      return;
    }

    #[cfg(all(unix, feature = "signal-hook"))] {
      if self.exit_requested.load(std::sync::atomic::Ordering::SeqCst) {
        ctx.flush();
        return;
      }
    }

    match self.input.read_frame(&video_info) {
      Ok(frame) => {
        match video_info.bit_depth {
          8 | 10 | 12 => {}
          _ => panic!("unknown input bit depth!")
        }
        self.count += 1;
        let _ = ctx.send_frame(Some(Arc::new(frame)));
      }
      _ => {
        ctx.flush();
      }
    };
  }
}

// Encode and write a frame.
// Returns frame information in a `Result`.
fn process_frame<T: Pixel, D: Decoder>(
  ctx: &mut Context<T>, output_file: &mut dyn Muxer,
  source: &mut Source<D>,
  mut y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>
) -> Option<Vec<FrameSummary>> {
  let y4m_details = source.input.get_video_details();
  let mut frame_summaries = Vec::new();
  let pkt_wrapped = ctx.receive_packet();
  match pkt_wrapped {
    Ok(pkt) => {
      output_file.write_frame(pkt.input_frameno as u64, pkt.data.as_ref());
      if let (Some(ref mut y4m_enc_uw), Some(ref rec)) = (y4m_enc.as_mut(), &pkt.rec) {
        write_y4m_frame(y4m_enc_uw, rec, y4m_details);
      }
      frame_summaries.push(pkt.into());
    }
    Err(EncoderStatus::NeedMoreData) => {
      source.read_frame(ctx, y4m_details);
    }
    Err(EncoderStatus::EnoughData) => {
      unreachable!();
    }
    Err(EncoderStatus::LimitReached) => {
      return None;
    }
    Err(EncoderStatus::Failure) => {
      panic!("Failed to encode video");
    }
    Err(EncoderStatus::Encoded) => {}
  }
  Some(frame_summaries)
}

fn write_stats_file<T: Pixel>(ctx: &Context<T>, filename: &Path) -> Result<(), io::Error> {
  let file = File::create(filename)?;
  let writer = BufWriter::new(file);
  serde_json::to_writer(writer, ctx.get_first_pass_data()).expect("Serialization should not fail");
  Ok(())
}

fn do_encode<T: Pixel, D: Decoder>(
  cfg: Config, verbose: bool, mut progress: ProgressInfo,
  output: &mut dyn Muxer,
  source: &mut Source<D>,
  mut y4m_enc: Option<y4m::Encoder<'_, Box<dyn Write>>>
) {
  let mut ctx: Context<T> = cfg.new_context();

  while let Some(frame_info) =
    process_frame(&mut ctx, &mut *output, source, y4m_enc.as_mut())
  {
    for frame in frame_info {
      progress.add_frame(frame);
      if verbose {
        eprintln!("{} - {}", frame, progress);
      } else {
        eprint!("\r{}                    ", progress);
      };
    }

    output.flush().unwrap();
  }

  if cfg.enc.pass == Some(1) {
    if let Err(e) =
      write_stats_file(&ctx, cfg.enc.stats_file.as_ref().unwrap())
    {
      eprintln!("\nError: Failed to write stats file! {}\n", e);
    }
  }
  eprint!("\n{}\n", progress.print_summary());
}

fn main() {
  let mut cli = parse_cli();
  let mut y4m_dec = y4m::decode(&mut cli.io.input).expect("input is not a y4m file");
  let video_info = y4m_dec.get_video_details();
  let y4m_enc = match cli.io.rec.as_mut() {
    Some(rec) => Some(
      y4m::encode(
        video_info.width,
        video_info.height,
        y4m::Ratio::new(video_info.time_base.den as usize, video_info.time_base.num as usize)
      ).with_colorspace(y4m_dec.get_colorspace())
        .write_header(rec)
        .unwrap()
    ),
    None => None
  };

  cli.enc.width = video_info.width;
  cli.enc.height = video_info.height;
  cli.enc.bit_depth = video_info.bit_depth;
  cli.enc.chroma_sampling = video_info.chroma_sampling;
  cli.enc.chroma_sample_position = video_info.chroma_sample_position;
  cli.enc.time_base = video_info.time_base;
  let cfg = Config {
    enc: cli.enc,
    threads: cli.threads,
  };

  eprintln!("{}x{} @ {}/{} fps",
    video_info.width,
    video_info.height,
    video_info.time_base.den,
    video_info.time_base.num
  );

  cli.io.output.write_header(
    video_info.width,
    video_info.height,
    video_info.time_base.den as usize,
    video_info.time_base.num as usize
  );

  let progress = ProgressInfo::new(
    Rational { num: video_info.time_base.den, den: video_info.time_base.num },
    if cli.limit == 0 { None } else { Some(cli.limit) },
      cfg.enc.show_psnr
  );

  for _ in 0..cli.skip {
    y4m_dec.read_frame().expect("Skipped more frames than in the input");
  }

  #[cfg(all(unix, feature = "signal-hook"))]
  let exit_requested = {
    use std::sync::atomic::*;
    let e  = Arc::new(AtomicBool::from(false));

    fn setup_signal(sig: i32, e: Arc<AtomicBool>) {
      unsafe {
        signal_hook::register(sig, move || {
          if e.load(Ordering::SeqCst) {
            std::process::exit(128 + sig);
          }
          e.store(true, Ordering::SeqCst);
          eprintln!("\rExit requested, flushing.\n");
        }).expect("Cannot register the signal hooks");
      }
    }

    setup_signal(signal_hook::SIGTERM, e.clone());
    setup_signal(signal_hook::SIGQUIT, e.clone());
    setup_signal(signal_hook::SIGINT, e.clone());

    e
  };

  #[cfg(all(unix, feature = "signal-hook"))]
  let mut source = Source {
    limit: cli.limit,
    input: y4m_dec,
    count: 0,
    exit_requested
  };
  #[cfg(not(all(unix, feature = "signal-hook")))]
  let mut source = Source { limit: cli.limit, input: y4m_dec, count: 0 };

  if video_info.bit_depth == 8 {
    do_encode::<u8, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg, cli.verbose, progress, &mut *cli.io.output, &mut source, y4m_enc
    )
  } else {
    do_encode::<u16, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg, cli.verbose, progress, &mut *cli.io.output, &mut source, y4m_enc
    )
  }
}
<commit_msg>Set Y4M pixel range to limited from CLI<commit_after>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![deny(bare_trait_objects)]

mod common;
mod decoder;
mod muxer;
use crate::common::*;
use rav1e::prelude::*;

use std::io;
use std::io::Write;
use std::io::Read;
use std::path::Path;
use std::sync::Arc;
use crate::decoder::Decoder;
use crate::decoder::VideoDetails;
use crate::muxer::*;
use std::fs::File;
use std::io::BufWriter;

struct Source<D: Decoder> {
 limit: usize,
 count: usize,
 input: D,
 #[cfg(all(unix, feature = "signal-hook"))]
 exit_requested: Arc<std::sync::atomic::AtomicBool>,
}

impl<D: Decoder> Source<D> {
  fn read_frame<T: Pixel>(&mut self, ctx: &mut Context<T>, video_info: VideoDetails) {
    if self.limit != 0 && self.count == self.limit {
      ctx.flush();
      return;
    }

    #[cfg(all(unix, feature = "signal-hook"))] {
      if self.exit_requested.load(std::sync::atomic::Ordering::SeqCst) {
        ctx.flush();
        return;
      }
    }

    match self.input.read_frame(&video_info) {
      Ok(frame) => {
        match video_info.bit_depth {
          8 | 10 | 12 => {}
          _ => panic!("unknown input bit depth!")
        }
        self.count += 1;
        let _ = ctx.send_frame(Some(Arc::new(frame)));
      }
      _ => {
        ctx.flush();
      }
    };
  }
}

// Encode and write a frame.
// Returns frame information in a `Result`.
fn process_frame<T: Pixel, D: Decoder>(
  ctx: &mut Context<T>, output_file: &mut dyn Muxer,
  source: &mut Source<D>,
  mut y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>
) -> Option<Vec<FrameSummary>> {
  let y4m_details = source.input.get_video_details();
  let mut frame_summaries = Vec::new();
  let pkt_wrapped = ctx.receive_packet();
  match pkt_wrapped {
    Ok(pkt) => {
      output_file.write_frame(pkt.input_frameno as u64, pkt.data.as_ref());
      if let (Some(ref mut y4m_enc_uw), Some(ref rec)) = (y4m_enc.as_mut(), &pkt.rec) {
        write_y4m_frame(y4m_enc_uw, rec, y4m_details);
      }
      frame_summaries.push(pkt.into());
    }
    Err(EncoderStatus::NeedMoreData) => {
      source.read_frame(ctx, y4m_details);
    }
    Err(EncoderStatus::EnoughData) => {
      unreachable!();
    }
    Err(EncoderStatus::LimitReached) => {
      return None;
    }
    Err(EncoderStatus::Failure) => {
      panic!("Failed to encode video");
    }
    Err(EncoderStatus::Encoded) => {}
  }
  Some(frame_summaries)
}

fn write_stats_file<T: Pixel>(ctx: &Context<T>, filename: &Path) -> Result<(), io::Error> {
  let file = File::create(filename)?;
  let writer = BufWriter::new(file);
  serde_json::to_writer(writer, ctx.get_first_pass_data()).expect("Serialization should not fail");
  Ok(())
}

fn do_encode<T: Pixel, D: Decoder>(
  cfg: Config, verbose: bool, mut progress: ProgressInfo,
  output: &mut dyn Muxer,
  source: &mut Source<D>,
  mut y4m_enc: Option<y4m::Encoder<'_, Box<dyn Write>>>
) {
  let mut ctx: Context<T> = cfg.new_context();

  while let Some(frame_info) =
    process_frame(&mut ctx, &mut *output, source, y4m_enc.as_mut())
  {
    for frame in frame_info {
      progress.add_frame(frame);
      if verbose {
        eprintln!("{} - {}", frame, progress);
      } else {
        eprint!("\r{}                    ", progress);
      };
    }

    output.flush().unwrap();
  }

  if cfg.enc.pass == Some(1) {
    if let Err(e) =
      write_stats_file(&ctx, cfg.enc.stats_file.as_ref().unwrap())
    {
      eprintln!("\nError: Failed to write stats file! {}\n", e);
    }
  }
  eprint!("\n{}\n", progress.print_summary());
}

fn main() {
  let mut cli = parse_cli();
  let mut y4m_dec = y4m::decode(&mut cli.io.input).expect("input is not a y4m file");
  let video_info = y4m_dec.get_video_details();
  let y4m_enc = match cli.io.rec.as_mut() {
    Some(rec) => Some(
      y4m::encode(
        video_info.width,
        video_info.height,
        y4m::Ratio::new(video_info.time_base.den as usize, video_info.time_base.num as usize)
      ).with_colorspace(y4m_dec.get_colorspace())
        .write_header(rec)
        .unwrap()
    ),
    None => None
  };

  cli.enc.width = video_info.width;
  cli.enc.height = video_info.height;
  cli.enc.bit_depth = video_info.bit_depth;
  cli.enc.chroma_sampling = video_info.chroma_sampling;
  cli.enc.chroma_sample_position = video_info.chroma_sample_position;

  // If no pixel range is specified via CLI, assume limited,
  // as it is the default for the Y4M format.
  if cli.enc.pixel_range == PixelRange::Unspecified {
    cli.enc.pixel_range = PixelRange::Limited;
  }

  cli.enc.time_base = video_info.time_base;
  let cfg = Config {
    enc: cli.enc,
    threads: cli.threads,
  };

  eprintln!("{}x{} @ {}/{} fps",
    video_info.width,
    video_info.height,
    video_info.time_base.den,
    video_info.time_base.num
  );

  cli.io.output.write_header(
    video_info.width,
    video_info.height,
    video_info.time_base.den as usize,
    video_info.time_base.num as usize
  );

  let progress = ProgressInfo::new(
    Rational { num: video_info.time_base.den, den: video_info.time_base.num },
    if cli.limit == 0 { None } else { Some(cli.limit) },
      cfg.enc.show_psnr
  );

  for _ in 0..cli.skip {
    y4m_dec.read_frame().expect("Skipped more frames than in the input");
  }

  #[cfg(all(unix, feature = "signal-hook"))]
  let exit_requested = {
    use std::sync::atomic::*;
    let e  = Arc::new(AtomicBool::from(false));

    fn setup_signal(sig: i32, e: Arc<AtomicBool>) {
      unsafe {
        signal_hook::register(sig, move || {
          if e.load(Ordering::SeqCst) {
            std::process::exit(128 + sig);
          }
          e.store(true, Ordering::SeqCst);
          eprintln!("\rExit requested, flushing.\n");
        }).expect("Cannot register the signal hooks");
      }
    }

    setup_signal(signal_hook::SIGTERM, e.clone());
    setup_signal(signal_hook::SIGQUIT, e.clone());
    setup_signal(signal_hook::SIGINT, e.clone());

    e
  };

  #[cfg(all(unix, feature = "signal-hook"))]
  let mut source = Source {
    limit: cli.limit,
    input: y4m_dec,
    count: 0,
    exit_requested
  };
  #[cfg(not(all(unix, feature = "signal-hook")))]
  let mut source = Source { limit: cli.limit, input: y4m_dec, count: 0 };

  if video_info.bit_depth == 8 {
    do_encode::<u8, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg, cli.verbose, progress, &mut *cli.io.output, &mut source, y4m_enc
    )
  } else {
    do_encode::<u16, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg, cli.verbose, progress, &mut *cli.io.output, &mut source, y4m_enc
    )
  }
}
<|endoftext|>


<commit_before>use syntax::ptr::P;
use syntax::ast::*;
use rustc::lint::{Context, LintPass, LintArray, Lint};
use rustc::middle::ty::{expr_ty, sty, ty_ptr, ty_rptr, mt};

declare_lint!(pub MUT_MUT, Warn,
              "Warn on usage of double-mut refs, e.g. '&mut &mut ...'");

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

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

	fn check_expr(&mut self, cx: &Context, expr: &Expr) {

		fn unwrap_addr(expr : &Expr) -> Option<&Expr> {
			match expr.node {
				ExprAddrOf(MutMutable, ref e) => Option::Some(e),
				_ => Option::None
			}
		}

		unwrap_addr(expr).map(|e| {
			if unwrap_addr(e).is_some() {
				cx.span_lint(MUT_MUT, expr.span,
					"We're not sure what this means, so if you know, please tell us.")
			} else {
				match expr_ty(cx.tcx, e).sty {
					ty_ptr(mt{ty: _, mutbl: MutMutable}) |
					ty_rptr(_, mt{ty: _, mutbl: MutMutable}) =>
						cx.span_lint(MUT_MUT, expr.span,
							"This expression mutably borrows a mutable reference. Consider direct reborrowing"),
					_ => ()
				}
			}
		});
	}

	fn check_ty(&mut self, cx: &Context, ty: &Ty) {
		if unwrap_mut(ty).and_then(unwrap_mut).is_some() {
			cx.span_lint(MUT_MUT, ty.span,
				"We're not sure what this means, so if you know, please tell us.")
		}
	}
}

fn unwrap_mut(ty : &Ty) -> Option<&Ty> {
	match ty.node {
		TyPtr(MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty),
		TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty),
		_ => Option::None
	}
}
<commit_msg>better messages<commit_after>use syntax::ptr::P;
use syntax::ast::*;
use rustc::lint::{Context, LintPass, LintArray, Lint};
use rustc::middle::ty::{expr_ty, sty, ty_ptr, ty_rptr, mt};

declare_lint!(pub MUT_MUT, Warn,
              "Warn on usage of double-mut refs, e.g. '&mut &mut ...'");

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

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

	fn check_expr(&mut self, cx: &Context, expr: &Expr) {

		fn unwrap_addr(expr : &Expr) -> Option<&Expr> {
			match expr.node {
				ExprAddrOf(MutMutable, ref e) => Option::Some(e),
				_ => Option::None
			}
		}

		unwrap_addr(expr).map(|e| {
			if unwrap_addr(e).is_some() {
				cx.span_lint(MUT_MUT, expr.span,
					"Generally you want to avoid &mut &mut _ if possible.")
			} else {
				match expr_ty(cx.tcx, e).sty {
					ty_ptr(mt{ty: _, mutbl: MutMutable}) |
					ty_rptr(_, mt{ty: _, mutbl: MutMutable}) =>
						cx.span_lint(MUT_MUT, expr.span,
							"This expression mutably borrows a mutable reference. Consider reborrowing"),
					_ => ()
				}
			}
		});
	}

	fn check_ty(&mut self, cx: &Context, ty: &Ty) {
		if unwrap_mut(ty).and_then(unwrap_mut).is_some() {
			cx.span_lint(MUT_MUT, ty.span,
				"Generally you want to avoid &mut &mut _ if possible.")
		}
	}
}

fn unwrap_mut(ty : &Ty) -> Option<&Ty> {
	match ty.node {
		TyPtr(MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty),
		TyRptr(_, MutTy{ ty: ref pty, mutbl: MutMutable }) => Option::Some(pty),
		_ => Option::None
	}
}
<|endoftext|>


<commit_before>use graph_algorithms as ga;
use nll_repr::repr;
use std::collections::BTreeMap;
use std::cell::RefCell;
use std::fmt;
use std::mem;
use std::iter;
use std::slice;

pub struct FuncGraph {
    func: repr::Func,
    start_block: BasicBlockIndex,
    blocks: Vec<BasicBlockKind>,
    successors: Vec<Vec<BasicBlockIndex>>,
    predecessors: Vec<Vec<BasicBlockIndex>>,
    block_indices: BTreeMap<repr::BasicBlock, BasicBlockIndex>,
}

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct BasicBlockIndex {
    index: usize,
}

#[derive(Copy, Clone, Debug)]
pub enum BasicBlockKind {
    Code(repr::BasicBlock),
    SkolemizedEnd(repr::RegionName),
}

#[derive(Copy, Clone, Debug)]
pub enum BasicBlockData<'a> {
    Code(&'a repr::BasicBlockData),
    SkolemizedEnd(repr::RegionName),
}

impl FuncGraph {
    pub fn new(func: repr::Func) -> Self {
        let blocks: Vec<_> = func.data
            .keys()
            .map(|&bb| BasicBlockKind::Code(bb))
            .collect();
        let block_indices: BTreeMap<_, _> = func.data
            .keys()
            .cloned()
            .enumerate()
            .map(|(index, block)| (block, BasicBlockIndex { index: index }))
            .collect();
        let mut predecessors: Vec<_> = (0..blocks.len()).map(|_| Vec::new()).collect();
        let mut successors: Vec<_> = (0..blocks.len()).map(|_| Vec::new()).collect();

        for (block, &index) in &block_indices {
            let data = &func.data[block];
            for successor in &data.successors {
                let successor_index = block_indices
                    .get(successor)
                    .cloned()
                    .unwrap_or_else(|| panic!("no index for {:?}", successor));
                successors[index.index].push(successor_index);
                predecessors[successor_index.index].push(index);
            }
        }

        let start_block = block_indices[&repr::BasicBlock::start()];

        FuncGraph {
            func: func,
            blocks: blocks,
            start_block: start_block,
            predecessors: predecessors,
            successors: successors,
            block_indices: block_indices,
        }
    }

    pub fn block(&self, name: repr::BasicBlock) -> BasicBlockIndex {
        self.block_indices[&name]
    }

    pub fn block_data(&self, index: BasicBlockIndex) -> BasicBlockData {
        match self.blocks[index.index] {
            BasicBlockKind::Code(block) => BasicBlockData::Code(&self.func.data[&block]),
            BasicBlockKind::SkolemizedEnd(r) => BasicBlockData::SkolemizedEnd(r),
        }
    }

    pub fn decls(&self) -> &[repr::VariableDecl] {
        &self.func.decls
    }

    pub fn assertions(&self) -> &[repr::Assertion] {
        &self.func.assertions
    }

    pub fn struct_decls(&self) -> &[repr::StructDecl] {
        &self.func.structs
    }
}

impl ga::Graph for FuncGraph {
    type Node = BasicBlockIndex;

    fn num_nodes(&self) -> usize {
        self.func.data.len()
    }

    fn start_node(&self) -> BasicBlockIndex {
        self.start_block
    }

    fn predecessors<'graph>(
        &'graph self,
        node: BasicBlockIndex,
    ) -> <Self as ga::GraphPredecessors<'graph>>::Iter {
        self.predecessors[node.index].iter().cloned()
    }

    fn successors<'graph>(
        &'graph self,
        node: BasicBlockIndex,
    ) -> <Self as ga::GraphSuccessors<'graph>>::Iter {
        self.successors[node.index].iter().cloned()
    }
}

impl<'graph> ga::GraphPredecessors<'graph> for FuncGraph {
    type Item = BasicBlockIndex;
    type Iter = iter::Cloned<slice::Iter<'graph, BasicBlockIndex>>;
}

impl<'graph> ga::GraphSuccessors<'graph> for FuncGraph {
    type Item = BasicBlockIndex;
    type Iter = iter::Cloned<slice::Iter<'graph, BasicBlockIndex>>;
}

impl ga::NodeIndex for BasicBlockIndex {}

impl From<usize> for BasicBlockIndex {
    fn from(v: usize) -> BasicBlockIndex {
        BasicBlockIndex { index: v }
    }
}

impl Into<usize> for BasicBlockIndex {
    fn into(self) -> usize {
        self.index
    }
}

thread_local! {
    static NAMES: RefCell<Vec<BasicBlockKind>> = RefCell::new(vec![])
}

pub fn with_graph<OP, R>(g: &FuncGraph, op: OP) -> R
where
    OP: FnOnce() -> R,
{
    NAMES.with(|names| {
        let old_names = mem::replace(&mut *names.borrow_mut(), g.blocks.clone());
        let result = op();
        *names.borrow_mut() = old_names;
        result
    })
}

impl fmt::Debug for BasicBlockIndex {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        NAMES.with(|names| {
            let names = names.borrow();
            if !names.is_empty() {
                match names[self.index] {
                    BasicBlockKind::Code(bb) => write!(fmt, "{}", bb),
                    BasicBlockKind::SkolemizedEnd(rn) => write!(fmt, "{}", rn),
                }
            } else {
                write!(fmt, "BB{}", self.index)
            }
        })
    }
}

impl<'a> BasicBlockData<'a> {
    pub fn actions(self) -> &'a [repr::Action] {
        match self {
            BasicBlockData::Code(d) => &d.actions,
            BasicBlockData::SkolemizedEnd(_) => &[],
        }
    }
}
<commit_msg>include skolemized end points in the graph<commit_after>use graph_algorithms as ga;
use nll_repr::repr;
use std::collections::BTreeMap;
use std::cell::RefCell;
use std::fmt;
use std::mem;
use std::iter;
use std::slice;

pub struct FuncGraph {
    func: repr::Func,
    start_block: BasicBlockIndex,
    blocks: Vec<BasicBlockKind>,
    successors: Vec<Vec<BasicBlockIndex>>,
    predecessors: Vec<Vec<BasicBlockIndex>>,
    block_indices: BTreeMap<repr::BasicBlock, BasicBlockIndex>,
    skolemized_end_indices: BTreeMap<repr::RegionName, BasicBlockIndex>,
}

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct BasicBlockIndex {
    index: usize,
}

#[derive(Copy, Clone, Debug)]
pub enum BasicBlockKind {
    Code(repr::BasicBlock),
    SkolemizedEnd(repr::RegionName),
}

#[derive(Copy, Clone, Debug)]
pub enum BasicBlockData<'a> {
    Code(&'a repr::BasicBlockData),
    SkolemizedEnd(repr::RegionName),
}

impl FuncGraph {
    pub fn new(func: repr::Func) -> Self {
        let blocks: Vec<_> = func.data
            .keys()
            .map(|&bb| BasicBlockKind::Code(bb))
            .chain(
                func.regions
                    .iter()
                    .map(|rd| BasicBlockKind::SkolemizedEnd(rd.name)),
            )
            .collect();
        let block_indices: BTreeMap<_, _> = func.data
            .keys()
            .cloned()
            .enumerate()
            .map(|(index, block)| (block, BasicBlockIndex { index: index }))
            .collect();
        let skolemized_end_indices: BTreeMap<_, _> = func.regions
            .iter()
            .enumerate()
            .map(|(index, rd)| {
                (
                    rd.name,
                    BasicBlockIndex {
                        index: index + block_indices.len(),
                    },
                )
            })
            .collect();
        let mut predecessors: Vec<_> = (0..blocks.len()).map(|_| Vec::new()).collect();
        let mut successors: Vec<_> = (0..blocks.len()).map(|_| Vec::new()).collect();

        for (block, &index) in &block_indices {
            let data = &func.data[block];
            for successor in &data.successors {
                let successor_index = block_indices
                    .get(successor)
                    .cloned()
                    .unwrap_or_else(|| panic!("no index for {:?}", successor));
                successors[index.index].push(successor_index);
                predecessors[successor_index.index].push(index);
            }
        }

        let start_block = block_indices[&repr::BasicBlock::start()];

        FuncGraph {
            func,
            blocks,
            start_block,
            predecessors,
            successors,
            block_indices,
            skolemized_end_indices,
        }
    }

    pub fn block(&self, name: repr::BasicBlock) -> BasicBlockIndex {
        self.block_indices[&name]
    }

    pub fn block_data(&self, index: BasicBlockIndex) -> BasicBlockData {
        match self.blocks[index.index] {
            BasicBlockKind::Code(block) => BasicBlockData::Code(&self.func.data[&block]),
            BasicBlockKind::SkolemizedEnd(r) => BasicBlockData::SkolemizedEnd(r),
        }
    }

    pub fn decls(&self) -> &[repr::VariableDecl] {
        &self.func.decls
    }

    pub fn assertions(&self) -> &[repr::Assertion] {
        &self.func.assertions
    }

    pub fn struct_decls(&self) -> &[repr::StructDecl] {
        &self.func.structs
    }
}

impl ga::Graph for FuncGraph {
    type Node = BasicBlockIndex;

    fn num_nodes(&self) -> usize {
        self.func.data.len()
    }

    fn start_node(&self) -> BasicBlockIndex {
        self.start_block
    }

    fn predecessors<'graph>(
        &'graph self,
        node: BasicBlockIndex,
    ) -> <Self as ga::GraphPredecessors<'graph>>::Iter {
        self.predecessors[node.index].iter().cloned()
    }

    fn successors<'graph>(
        &'graph self,
        node: BasicBlockIndex,
    ) -> <Self as ga::GraphSuccessors<'graph>>::Iter {
        self.successors[node.index].iter().cloned()
    }
}

impl<'graph> ga::GraphPredecessors<'graph> for FuncGraph {
    type Item = BasicBlockIndex;
    type Iter = iter::Cloned<slice::Iter<'graph, BasicBlockIndex>>;
}

impl<'graph> ga::GraphSuccessors<'graph> for FuncGraph {
    type Item = BasicBlockIndex;
    type Iter = iter::Cloned<slice::Iter<'graph, BasicBlockIndex>>;
}

impl ga::NodeIndex for BasicBlockIndex {}

impl From<usize> for BasicBlockIndex {
    fn from(v: usize) -> BasicBlockIndex {
        BasicBlockIndex { index: v }
    }
}

impl Into<usize> for BasicBlockIndex {
    fn into(self) -> usize {
        self.index
    }
}

thread_local! {
    static NAMES: RefCell<Vec<BasicBlockKind>> = RefCell::new(vec![])
}

pub fn with_graph<OP, R>(g: &FuncGraph, op: OP) -> R
where
    OP: FnOnce() -> R,
{
    NAMES.with(|names| {
        let old_names = mem::replace(&mut *names.borrow_mut(), g.blocks.clone());
        let result = op();
        *names.borrow_mut() = old_names;
        result
    })
}

impl fmt::Debug for BasicBlockIndex {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        NAMES.with(|names| {
            let names = names.borrow();
            if !names.is_empty() {
                match names[self.index] {
                    BasicBlockKind::Code(bb) => write!(fmt, "{}", bb),
                    BasicBlockKind::SkolemizedEnd(rn) => write!(fmt, "{}", rn),
                }
            } else {
                write!(fmt, "BB{}", self.index)
            }
        })
    }
}

impl<'a> BasicBlockData<'a> {
    pub fn actions(self) -> &'a [repr::Action] {
        match self {
            BasicBlockData::Code(d) => &d.actions,
            BasicBlockData::SkolemizedEnd(_) => &[],
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap,BTreeMap};
use std::borrow::Borrow;
use std::hash::Hash;

/// basic protocol for maps.
pub trait Map<K,V> where Self:Sized {
    /// a map maps from keys to values.
    fn fun<'a,Q:?Sized>(&'a self) -> Box<Fn(&Q) -> Option<&'a V> + 'a> where K:Borrow<Q>, Q:Hash+Ord;

    /// adds entry `kv`.
    fn inc(self, kv:(K,V)) -> Self;

    /// removes key `k`.
    fn dec<Q:?Sized>(self, k:&Q) -> Self where K:Borrow<Q>, Q:Hash+Ord;

    /// pours another collection into this one.
    fn plus<I>(self, coll:I) -> Self where I:IntoIterator<Item = (K,V)>
    { coll.into_iter().fold(self, Map::inc)}

    /// `clear`.
    fn zero(self) -> Self;

    /// `shrink_to_fit`.
    fn shrink(self) -> Self;

    /// like clojure's [update](http://clojuredocs.org/clojure.core/update).
    fn update<F>(self, k:K, f:F) -> Self where F:FnOnce(Option<V>) -> V ;

    /// like clojure's [merge-with](http://clojuredocs.org/clojure.core/merge-with).
    fn merge<M,F>(self, other:M, mut f:F) -> Self where M:IntoIterator<Item = (K,V)>, F:FnMut(V,V) -> V
    { other.into_iter().fold(self, |m,(k,v)| Map::update(m, k, |mu| match mu { Some(u) => f(u,v), None => v }))}
}

impl<K,V> Map<K,V> for HashMap<K,V> where K:Hash+Eq {
    fn fun<'a,Q:?Sized>(&'a self) -> Box<Fn(&Q) -> Option<&'a V> + 'a> where K:Borrow<Q>, Q:Hash+Eq
    { Box::new(move |k| self.get(k))}

    fn inc(mut self, kv:(K,V)) -> Self
    { self.insert(kv.0, kv.1); self }

    fn dec<Q:?Sized>(mut self, k:&Q) -> Self where K:Borrow<Q>, Q:Hash+Eq
    { self.remove(k); self }

    fn zero(mut self) -> Self
    { self.clear(); self }

    fn shrink(mut self) -> Self
    { self.shrink_to_fit(); self }

    fn update<F>(mut self, k:K, f:F) -> Self where F:FnOnce(Option<V>) -> V
    { let v = f(self.remove(&k)); Map::inc(self,(k,v))}
}

impl<K,V> Map<K,V> for BTreeMap<K,V> where K:Ord {
    fn fun<'a,Q:?Sized>(&'a self) -> Box<Fn(&Q) -> Option<&'a V> + 'a> where K:Borrow<Q>, Q:Ord
    { Box::new(move |k| self.get(k))}

    fn inc(mut self, kv:(K,V)) -> Self
    { self.insert(kv.0, kv.1); self }

    fn dec<Q:?Sized>(mut self, k:&Q) -> Self where K:Borrow<Q>, Q:Ord
    { self.remove(k); self }

    fn zero(mut self) -> Self
    { self.clear(); self }

    fn shrink(self) -> Self
    { self }

    fn update<F>(mut self, k:K, f:F) -> Self where F:FnOnce(Option<V>) -> V
    { let v = f(self.remove(&k)); Map::inc(self,(k,v))}
}
<commit_msg>examples<commit_after>use std::collections::{HashMap,BTreeMap};
use std::borrow::Borrow;
use std::hash::Hash;

/// basic protocol for maps.
pub trait Map<K,V> where Self:Sized {
    /// a map maps from keys to values.
    fn fun<'a,Q:?Sized>(&'a self) -> Box<Fn(&Q) -> Option<&'a V> + 'a> where K:Borrow<Q>, Q:Hash+Ord;

    /// adds entry `kv`.
    fn inc(self, kv:(K,V)) -> Self;

    /// removes key `k`.
    fn dec<Q:?Sized>(self, k:&Q) -> Self where K:Borrow<Q>, Q:Hash+Ord;

    /// pours another collection into this one.
    fn plus<I>(self, coll:I) -> Self where I:IntoIterator<Item = (K,V)>
    { coll.into_iter().fold(self, Map::inc)}

    /// `clear`.
    fn zero(self) -> Self;

    /// `shrink_to_fit`.
    fn shrink(self) -> Self;

    /// like clojure's [update](http://clojuredocs.org/clojure.core/update).
    /// # example
    /// ```
    /// use protocoll::Map;
    /// use std::collections::HashMap;
    /// let m = [0,0,0,1,1,0,0,0].iter()
    ///    .fold(HashMap::new(), |m,&k| Map::update
    ///          (m,k, |opt_n| 1 + opt_n.unwrap_or(0)));
    /// assert_eq!(6, m[&0]);
    /// assert_eq!(2, m[&1]);
    /// ```
    fn update<F>(self, k:K, f:F) -> Self where F:FnOnce(Option<V>) -> V ;

    /// like clojure's [merge-with](http://clojuredocs.org/clojure.core/merge-with).
    /// # example
    /// ```
    /// use protocoll::Map;
    /// use std::collections::HashMap;
    /// use std::ops::Add;
    /// let m = [0,0,0,1,1,0,0,0].iter()
    ///    .fold(HashMap::new(), |m,&k| Map::update
    ///          (m,k, |opt_n| 1 + opt_n.unwrap_or(0)));
    /// let m = Map::merge(m.clone(), m, usize::add);
    /// assert_eq!(12, m[&0]);
    /// assert_eq!(4, m[&1]);
    /// ```
    fn merge<M,F>(self, other:M, mut f:F) -> Self where M:IntoIterator<Item = (K,V)>, F:FnMut(V,V) -> V
    { other.into_iter().fold(self, |m,(k,v)| Map::update(m, k, |opt_u| match opt_u { Some(u) => f(u,v), None => v }))}
}

impl<K,V> Map<K,V> for HashMap<K,V> where K:Hash+Eq {
    fn fun<'a,Q:?Sized>(&'a self) -> Box<Fn(&Q) -> Option<&'a V> + 'a> where K:Borrow<Q>, Q:Hash+Eq
    { Box::new(move |k| self.get(k))}

    fn inc(mut self, kv:(K,V)) -> Self
    { self.insert(kv.0, kv.1); self }

    fn dec<Q:?Sized>(mut self, k:&Q) -> Self where K:Borrow<Q>, Q:Hash+Eq
    { self.remove(k); self }

    fn zero(mut self) -> Self
    { self.clear(); self }

    fn shrink(mut self) -> Self
    { self.shrink_to_fit(); self }

    fn update<F>(mut self, k:K, f:F) -> Self where F:FnOnce(Option<V>) -> V
    { let v = f(self.remove(&k)); Map::inc(self,(k,v))}
}

impl<K,V> Map<K,V> for BTreeMap<K,V> where K:Ord {
    fn fun<'a,Q:?Sized>(&'a self) -> Box<Fn(&Q) -> Option<&'a V> + 'a> where K:Borrow<Q>, Q:Ord
    { Box::new(move |k| self.get(k))}

    fn inc(mut self, kv:(K,V)) -> Self
    { self.insert(kv.0, kv.1); self }

    fn dec<Q:?Sized>(mut self, k:&Q) -> Self where K:Borrow<Q>, Q:Ord
    { self.remove(k); self }

    fn zero(mut self) -> Self
    { self.clear(); self }

    fn shrink(self) -> Self
    { self }

    fn update<F>(mut self, k:K, f:F) -> Self where F:FnOnce(Option<V>) -> V
    { let v = f(self.remove(&k)); Map::inc(self,(k,v))}
}
<|endoftext|>


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

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

use getopts::Options;
use std::cmp::Ordering;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Read, stdin, Stdin};
use std::path::Path;

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

fn mkdelim(col: usize, opts: &getopts::Matches) -> String {
    let mut s = String::new();
    let delim = match opts.opt_str("output-delimiter") {
        Some(d) => d.clone(),
        None => "\t".to_owned(),
    };

    if col > 1 && !opts.opt_present("1") {
        s.push_str(delim.as_ref());
    }
    if col > 2 && !opts.opt_present("2") {
        s.push_str(delim.as_ref());
    }

    s
}

fn ensure_nl(line: &mut String) {
    match line.chars().last() {
        Some('\n') => (),
        _ => line.push_str("\n")
    }
}

enum LineReader {
    Stdin(Stdin),
    FileIn(BufReader<File>)
}

impl LineReader {
    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
        match *self {
            LineReader::Stdin(ref mut r)  => r.read_line(buf),
            LineReader::FileIn(ref mut r) => r.read_line(buf),
        }
    }
}

fn comm(a: &mut LineReader, b: &mut LineReader, opts: &getopts::Matches) {

    let delim : Vec<String> = (0 .. 4).map(|col| mkdelim(col, opts)).collect();

    let mut ra = &mut String::new();
    let mut na = a.read_line(ra);
    let mut rb = &mut String::new();
    let mut nb = b.read_line(rb);

    while na.is_ok() || nb.is_ok() {
        let ord = match (na.is_ok(), nb.is_ok()) {
            (false, true)  => Ordering::Greater,
            (true , false) => Ordering::Less,
            (true , true) => match(&na, &nb) {
                (&Ok(0), &Ok(0)) => break,
                (&Ok(0), _) => Ordering::Greater,
                (_, &Ok(0)) => Ordering::Less,
                _ =>  ra.cmp(&rb),
            },
            _ => unreachable!(),
        };

        match ord {
            Ordering::Less => {
                if !opts.opt_present("1") {
                    ensure_nl(ra);
                    print!("{}{}", delim[1], ra);
                }
                ra.clear();
                na = a.read_line(ra);
            },
            Ordering::Greater => {
                if !opts.opt_present("2") {
                    ensure_nl(rb);
                    print!("{}{}", delim[2], rb);
                }
                rb.clear();
                nb = b.read_line(rb);
            },
            Ordering::Equal => {
                if !opts.opt_present("3") {
                    ensure_nl(ra);
                    print!("{}{}", delim[3], ra);
                }
                ra.clear();
                rb.clear();
                na = a.read_line(ra);
                nb = b.read_line(rb);
            }
        }
    }
}

fn open_file(name: &str) -> io::Result<LineReader> {
    match name {
        "-" => Ok(LineReader::Stdin(stdin())),
        _  => {
            let f = try!(File::open(&Path::new(name)));
            Ok(LineReader::FileIn(BufReader::new(f)))
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();
    opts.optflag("1", "", "suppress column 1 (lines uniq to FILE1)");
    opts.optflag("2", "", "suppress column 2 (lines uniq to FILE2)");
    opts.optflag("3", "", "suppress column 3 (lines that appear in both files)");
    opts.optopt("", "output-delimiter", "separate columns with STR", "STR");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

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

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

    if matches.opt_present("help") || matches.free.len() != 2 {
        let msg = format!("{0} {1}

Usage:
  {0} [OPTIONS] FILE1 FILE2

Compare sorted files line by line.", NAME, VERSION);

        print!("{}", opts.usage(&msg));

        if matches.free.len() != 2 {
            return 1;
        }
        return 0;
    }

    let mut f1 = open_file(matches.free[0].as_ref()).unwrap();
    let mut f2 = open_file(matches.free[1].as_ref()).unwrap();

    comm(&mut f1, &mut f2, &matches);

    0
}
<commit_msg>comm: remove unused import<commit_after>#![crate_name = "uu_comm"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

use getopts::Options;
use std::cmp::Ordering;
use std::fs::File;
use std::io::{self, BufRead, BufReader, stdin, Stdin};
use std::path::Path;

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

fn mkdelim(col: usize, opts: &getopts::Matches) -> String {
    let mut s = String::new();
    let delim = match opts.opt_str("output-delimiter") {
        Some(d) => d.clone(),
        None => "\t".to_owned(),
    };

    if col > 1 && !opts.opt_present("1") {
        s.push_str(delim.as_ref());
    }
    if col > 2 && !opts.opt_present("2") {
        s.push_str(delim.as_ref());
    }

    s
}

fn ensure_nl(line: &mut String) {
    match line.chars().last() {
        Some('\n') => (),
        _ => line.push_str("\n")
    }
}

enum LineReader {
    Stdin(Stdin),
    FileIn(BufReader<File>)
}

impl LineReader {
    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
        match *self {
            LineReader::Stdin(ref mut r)  => r.read_line(buf),
            LineReader::FileIn(ref mut r) => r.read_line(buf),
        }
    }
}

fn comm(a: &mut LineReader, b: &mut LineReader, opts: &getopts::Matches) {

    let delim : Vec<String> = (0 .. 4).map(|col| mkdelim(col, opts)).collect();

    let mut ra = &mut String::new();
    let mut na = a.read_line(ra);
    let mut rb = &mut String::new();
    let mut nb = b.read_line(rb);

    while na.is_ok() || nb.is_ok() {
        let ord = match (na.is_ok(), nb.is_ok()) {
            (false, true)  => Ordering::Greater,
            (true , false) => Ordering::Less,
            (true , true) => match(&na, &nb) {
                (&Ok(0), &Ok(0)) => break,
                (&Ok(0), _) => Ordering::Greater,
                (_, &Ok(0)) => Ordering::Less,
                _ =>  ra.cmp(&rb),
            },
            _ => unreachable!(),
        };

        match ord {
            Ordering::Less => {
                if !opts.opt_present("1") {
                    ensure_nl(ra);
                    print!("{}{}", delim[1], ra);
                }
                ra.clear();
                na = a.read_line(ra);
            },
            Ordering::Greater => {
                if !opts.opt_present("2") {
                    ensure_nl(rb);
                    print!("{}{}", delim[2], rb);
                }
                rb.clear();
                nb = b.read_line(rb);
            },
            Ordering::Equal => {
                if !opts.opt_present("3") {
                    ensure_nl(ra);
                    print!("{}{}", delim[3], ra);
                }
                ra.clear();
                rb.clear();
                na = a.read_line(ra);
                nb = b.read_line(rb);
            }
        }
    }
}

fn open_file(name: &str) -> io::Result<LineReader> {
    match name {
        "-" => Ok(LineReader::Stdin(stdin())),
        _  => {
            let f = try!(File::open(&Path::new(name)));
            Ok(LineReader::FileIn(BufReader::new(f)))
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();
    opts.optflag("1", "", "suppress column 1 (lines uniq to FILE1)");
    opts.optflag("2", "", "suppress column 2 (lines uniq to FILE2)");
    opts.optflag("3", "", "suppress column 3 (lines that appear in both files)");
    opts.optopt("", "output-delimiter", "separate columns with STR", "STR");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

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

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

    if matches.opt_present("help") || matches.free.len() != 2 {
        let msg = format!("{0} {1}

Usage:
  {0} [OPTIONS] FILE1 FILE2

Compare sorted files line by line.", NAME, VERSION);

        print!("{}", opts.usage(&msg));

        if matches.free.len() != 2 {
            return 1;
        }
        return 0;
    }

    let mut f1 = open_file(matches.free[0].as_ref()).unwrap();
    let mut f2 = open_file(matches.free[1].as_ref()).unwrap();

    comm(&mut f1, &mut f2, &matches);

    0
}
<|endoftext|>