<commit_before>use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
use crate::hir::{self, intravisit, HirId, ItemLocalId};
use syntax::ast::NodeId;
use crate::hir::itemlikevisit::ItemLikeVisitor;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::{Lock, ParallelIterator, par_iter};

pub fn check_crate<'hir>(hir_map: &hir::map::Map<'hir>) {
    hir_map.dep_graph.assert_ignored();

    let errors = Lock::new(Vec::new());

    par_iter(&hir_map.krate().modules).for_each(|(module_id, _)| {
        hir_map.visit_item_likes_in_module(hir_map.local_def_id(*module_id), &mut OuterVisitor {
            hir_map,
            errors: &errors,
        });
    });

    let errors = errors.into_inner();

    if !errors.is_empty() {
        let message = errors
            .iter()
            .fold(String::new(), |s1, s2| s1 + "\n" + s2);
        bug!("{}", message);
    }
}

struct HirIdValidator<'a, 'hir: 'a> {
    hir_map: &'a hir::map::Map<'hir>,
    owner_def_index: Option<DefIndex>,
    hir_ids_seen: FxHashSet<ItemLocalId>,
    errors: &'a Lock<Vec<String>>,
}

struct OuterVisitor<'a, 'hir: 'a> {
    hir_map: &'a hir::map::Map<'hir>,
    errors: &'a Lock<Vec<String>>,
}

impl<'a, 'hir: 'a> OuterVisitor<'a, 'hir> {
    fn new_inner_visitor(&self,
                         hir_map: &'a hir::map::Map<'hir>)
                         -> HirIdValidator<'a, 'hir> {
        HirIdValidator {
            hir_map,
            owner_def_index: None,
            hir_ids_seen: Default::default(),
            errors: self.errors,
        }
    }
}

impl<'a, 'hir: 'a> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> {
    fn visit_item(&mut self, i: &'hir hir::Item) {
        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
        inner_visitor.check(i.hir_id, |this| intravisit::walk_item(this, i));
    }

    fn visit_trait_item(&mut self, i: &'hir hir::TraitItem) {
        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
        inner_visitor.check(i.hir_id, |this| intravisit::walk_trait_item(this, i));
    }

    fn visit_impl_item(&mut self, i: &'hir hir::ImplItem) {
        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
        inner_visitor.check(i.hir_id, |this| intravisit::walk_impl_item(this, i));
    }
}

impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> {
    #[cold]
    #[inline(never)]
    fn error(&self, f: impl FnOnce() -> String) {
        self.errors.lock().push(f());
    }

    fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self,
                                                       hir_id: HirId,
                                                       walk: F) {
        assert!(self.owner_def_index.is_none());
        let owner_def_index = self.hir_map.local_def_id_from_hir_id(hir_id).index;
        self.owner_def_index = Some(owner_def_index);
        walk(self);

        if owner_def_index == CRATE_DEF_INDEX {
            return;
        }

        // There's always at least one entry for the owning item itself
        let max = self.hir_ids_seen
                      .iter()
                      .map(|local_id| local_id.as_usize())
                      .max()
                      .expect("owning item has no entry");

        if max != self.hir_ids_seen.len() - 1 {
            // Collect the missing ItemLocalIds
            let missing: Vec<_> = (0 ..= max as u32)
              .filter(|&i| !self.hir_ids_seen.contains(&ItemLocalId::from_u32(i)))
              .collect();

            // Try to map those to something more useful
            let mut missing_items = Vec::with_capacity(missing.len());

            for local_id in missing {
                let hir_id = HirId {
                    owner: owner_def_index,
                    local_id: ItemLocalId::from_u32(local_id),
                };

                trace!("missing hir id {:#?}", hir_id);

                // We are already in ICE mode here, so doing a linear search
                // should be fine.
                let (node_id, _) = self.hir_map
                                       .definitions()
                                       .node_to_hir_id
                                       .iter()
                                       .enumerate()
                                       .find(|&(_, &entry)| hir_id == entry)
                                       .expect("no node_to_hir_id entry");
                let node_id = NodeId::from_usize(node_id);
                let hir_id = self.hir_map.node_to_hir_id(node_id);
                missing_items.push(format!("[local_id: {}, node:{}]",
                                           local_id,
                                           self.hir_map.node_to_string(hir_id)));
            }
            self.error(|| format!(
                "ItemLocalIds not assigned densely in {}. \
                Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}",
                self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(),
                max,
                missing_items,
                self.hir_ids_seen
                    .iter()
                    .map(|&local_id| HirId {
                        owner: owner_def_index,
                        local_id,
                    })
                    .map(|h| format!("({:?} {})", h, self.hir_map.node_to_string(h)))
                    .collect::<Vec<_>>()));
        }
    }
}

impl<'a, 'hir: 'a> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {

    fn nested_visit_map<'this>(&'this mut self)
                               -> intravisit::NestedVisitorMap<'this, 'hir> {
        intravisit::NestedVisitorMap::OnlyBodies(self.hir_map)
    }

    fn visit_id(&mut self, hir_id: HirId) {
        let owner = self.owner_def_index.expect("no owner_def_index");

        if hir_id == hir::DUMMY_HIR_ID {
            self.error(|| format!("HirIdValidator: HirId {:?} is invalid",
                                  self.hir_map.node_to_string(hir_id)));
            return;
        }

        if owner != hir_id.owner {
            self.error(|| format!(
                "HirIdValidator: The recorded owner of {} is {} instead of {}",
                self.hir_map.node_to_string(hir_id),
                self.hir_map.def_path(DefId::local(hir_id.owner)).to_string_no_crate(),
                self.hir_map.def_path(DefId::local(owner)).to_string_no_crate()));
        }

        self.hir_ids_seen.insert(hir_id.local_id);
    }

    fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) {
        // Explicitly do nothing here. ImplItemRefs contain hir::Visibility
        // values that actually belong to an ImplItem instead of the ItemKind::Impl
        // we are currently in. So for those it's correct that they have a
        // different owner.
    }
}
<commit_msg>simplify ICE handling in HirIdValidator<commit_after>use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
use crate::hir::{self, intravisit, HirId, ItemLocalId};
use crate::hir::itemlikevisit::ItemLikeVisitor;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::{Lock, ParallelIterator, par_iter};

pub fn check_crate<'hir>(hir_map: &hir::map::Map<'hir>) {
    hir_map.dep_graph.assert_ignored();

    let errors = Lock::new(Vec::new());

    par_iter(&hir_map.krate().modules).for_each(|(module_id, _)| {
        hir_map.visit_item_likes_in_module(hir_map.local_def_id(*module_id), &mut OuterVisitor {
            hir_map,
            errors: &errors,
        });
    });

    let errors = errors.into_inner();

    if !errors.is_empty() {
        let message = errors
            .iter()
            .fold(String::new(), |s1, s2| s1 + "\n" + s2);
        bug!("{}", message);
    }
}

struct HirIdValidator<'a, 'hir: 'a> {
    hir_map: &'a hir::map::Map<'hir>,
    owner_def_index: Option<DefIndex>,
    hir_ids_seen: FxHashSet<ItemLocalId>,
    errors: &'a Lock<Vec<String>>,
}

struct OuterVisitor<'a, 'hir: 'a> {
    hir_map: &'a hir::map::Map<'hir>,
    errors: &'a Lock<Vec<String>>,
}

impl<'a, 'hir: 'a> OuterVisitor<'a, 'hir> {
    fn new_inner_visitor(&self,
                         hir_map: &'a hir::map::Map<'hir>)
                         -> HirIdValidator<'a, 'hir> {
        HirIdValidator {
            hir_map,
            owner_def_index: None,
            hir_ids_seen: Default::default(),
            errors: self.errors,
        }
    }
}

impl<'a, 'hir: 'a> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> {
    fn visit_item(&mut self, i: &'hir hir::Item) {
        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
        inner_visitor.check(i.hir_id, |this| intravisit::walk_item(this, i));
    }

    fn visit_trait_item(&mut self, i: &'hir hir::TraitItem) {
        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
        inner_visitor.check(i.hir_id, |this| intravisit::walk_trait_item(this, i));
    }

    fn visit_impl_item(&mut self, i: &'hir hir::ImplItem) {
        let mut inner_visitor = self.new_inner_visitor(self.hir_map);
        inner_visitor.check(i.hir_id, |this| intravisit::walk_impl_item(this, i));
    }
}

impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> {
    #[cold]
    #[inline(never)]
    fn error(&self, f: impl FnOnce() -> String) {
        self.errors.lock().push(f());
    }

    fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self,
                                                       hir_id: HirId,
                                                       walk: F) {
        assert!(self.owner_def_index.is_none());
        let owner_def_index = self.hir_map.local_def_id_from_hir_id(hir_id).index;
        self.owner_def_index = Some(owner_def_index);
        walk(self);

        if owner_def_index == CRATE_DEF_INDEX {
            return;
        }

        // There's always at least one entry for the owning item itself
        let max = self.hir_ids_seen
                      .iter()
                      .map(|local_id| local_id.as_usize())
                      .max()
                      .expect("owning item has no entry");

        if max != self.hir_ids_seen.len() - 1 {
            // Collect the missing ItemLocalIds
            let missing: Vec<_> = (0 ..= max as u32)
              .filter(|&i| !self.hir_ids_seen.contains(&ItemLocalId::from_u32(i)))
              .collect();

            // Try to map those to something more useful
            let mut missing_items = Vec::with_capacity(missing.len());

            for local_id in missing {
                let hir_id = HirId {
                    owner: owner_def_index,
                    local_id: ItemLocalId::from_u32(local_id),
                };

                trace!("missing hir id {:#?}", hir_id);

                missing_items.push(format!("[local_id: {}, node:{}]",
                                           local_id,
                                           self.hir_map.node_to_string(hir_id)));
            }
            self.error(|| format!(
                "ItemLocalIds not assigned densely in {}. \
                Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}",
                self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(),
                max,
                missing_items,
                self.hir_ids_seen
                    .iter()
                    .map(|&local_id| HirId {
                        owner: owner_def_index,
                        local_id,
                    })
                    .map(|h| format!("({:?} {})", h, self.hir_map.node_to_string(h)))
                    .collect::<Vec<_>>()));
        }
    }
}

impl<'a, 'hir: 'a> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {

    fn nested_visit_map<'this>(&'this mut self)
                               -> intravisit::NestedVisitorMap<'this, 'hir> {
        intravisit::NestedVisitorMap::OnlyBodies(self.hir_map)
    }

    fn visit_id(&mut self, hir_id: HirId) {
        let owner = self.owner_def_index.expect("no owner_def_index");

        if hir_id == hir::DUMMY_HIR_ID {
            self.error(|| format!("HirIdValidator: HirId {:?} is invalid",
                                  self.hir_map.node_to_string(hir_id)));
            return;
        }

        if owner != hir_id.owner {
            self.error(|| format!(
                "HirIdValidator: The recorded owner of {} is {} instead of {}",
                self.hir_map.node_to_string(hir_id),
                self.hir_map.def_path(DefId::local(hir_id.owner)).to_string_no_crate(),
                self.hir_map.def_path(DefId::local(owner)).to_string_no_crate()));
        }

        self.hir_ids_seen.insert(hir_id.local_id);
    }

    fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) {
        // Explicitly do nothing here. ImplItemRefs contain hir::Visibility
        // values that actually belong to an ImplItem instead of the ItemKind::Impl
        // we are currently in. So for those it's correct that they have a
        // different owner.
    }
}
<|endoftext|>


<commit_before>//! Intrinsics and other functions that the miri engine executes without
//! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
//! and miri.

use syntax::symbol::Symbol;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, Primitive, Size};
use rustc::mir::BinOp;
use rustc::mir::interpret::{
    EvalResult, InterpError, Scalar,
};

use super::{
    Machine, PlaceTy, OpTy, InterpretCx,
};

mod type_name;

pub use type_name::*;

fn numeric_intrinsic<'tcx, Tag>(
    name: &str,
    bits: u128,
    kind: Primitive,
) -> EvalResult<'tcx, Scalar<Tag>> {
    let size = match kind {
        Primitive::Int(integer, _) => integer.size(),
        _ => bug!("invalid `{}` argument: {:?}", name, bits),
    };
    let extra = 128 - size.bits() as u128;
    let bits_out = match name {
        "ctpop" => bits.count_ones() as u128,
        "ctlz" => bits.leading_zeros() as u128 - extra,
        "cttz" => (bits << extra).trailing_zeros() as u128 - extra,
        "bswap" => (bits << extra).swap_bytes(),
        "bitreverse" => (bits << extra).reverse_bits(),
        _ => bug!("not a numeric intrinsic: {}", name),
    };
    Ok(Scalar::from_uint(bits_out, size))
}

impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
    /// Returns `true` if emulation happened.
    pub fn emulate_intrinsic(
        &mut self,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, M::PointerTag>],
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx, bool> {
        let substs = instance.substs;

        let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
        match intrinsic_name {
            "min_align_of" => {
                let elem_ty = substs.type_at(0);
                let elem_align = self.layout_of(elem_ty)?.align.abi.bytes();
                let align_val = Scalar::from_uint(elem_align, dest.layout.size);
                self.write_scalar(align_val, dest)?;
            }

            "needs_drop" => {
                let ty = substs.type_at(0);
                let ty_needs_drop = ty.needs_drop(self.tcx.tcx, self.param_env);
                let val = Scalar::from_bool(ty_needs_drop);
                self.write_scalar(val, dest)?;
            }

            "size_of" => {
                let ty = substs.type_at(0);
                let size = self.layout_of(ty)?.size.bytes() as u128;
                let size_val = Scalar::from_uint(size, dest.layout.size);
                self.write_scalar(size_val, dest)?;
            }

            "type_id" => {
                let ty = substs.type_at(0);
                let type_id = self.tcx.type_id_hash(ty) as u128;
                let id_val = Scalar::from_uint(type_id, dest.layout.size);
                self.write_scalar(id_val, dest)?;
            }
            | "ctpop"
            | "cttz"
            | "cttz_nonzero"
            | "ctlz"
            | "ctlz_nonzero"
            | "bswap"
            | "bitreverse" => {
                let ty = substs.type_at(0);
                let layout_of = self.layout_of(ty)?;
                let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?;
                let kind = match layout_of.abi {
                    ty::layout::Abi::Scalar(ref scalar) => scalar.value,
                    _ => Err(::rustc::mir::interpret::InterpError::TypeNotPrimitive(ty))?,
                };
                let out_val = if intrinsic_name.ends_with("_nonzero") {
                    if bits == 0 {
                        return err!(Intrinsic(format!("{} called on 0", intrinsic_name)));
                    }
                    numeric_intrinsic(intrinsic_name.trim_end_matches("_nonzero"), bits, kind)?
                } else {
                    numeric_intrinsic(intrinsic_name, bits, kind)?
                };
                self.write_scalar(out_val, dest)?;
            }
            | "overflowing_add"
            | "overflowing_sub"
            | "overflowing_mul"
            | "add_with_overflow"
            | "sub_with_overflow"
            | "mul_with_overflow" => {
                let lhs = self.read_immediate(args[0])?;
                let rhs = self.read_immediate(args[1])?;
                let (bin_op, ignore_overflow) = match intrinsic_name {
                    "overflowing_add" => (BinOp::Add, true),
                    "overflowing_sub" => (BinOp::Sub, true),
                    "overflowing_mul" => (BinOp::Mul, true),
                    "add_with_overflow" => (BinOp::Add, false),
                    "sub_with_overflow" => (BinOp::Sub, false),
                    "mul_with_overflow" => (BinOp::Mul, false),
                    _ => bug!("Already checked for int ops")
                };
                if ignore_overflow {
                    self.binop_ignore_overflow(bin_op, lhs, rhs, dest)?;
                } else {
                    self.binop_with_overflow(bin_op, lhs, rhs, dest)?;
                }
            }
            "saturating_add" | "saturating_sub" => {
                let l = self.read_immediate(args[0])?;
                let r = self.read_immediate(args[1])?;
                let is_add = intrinsic_name == "saturating_add";
                let (val, overflowed) = self.binary_op(if is_add {
                    BinOp::Add
                } else {
                    BinOp::Sub
                }, l, r)?;
                let val = if overflowed {
                    let num_bits = l.layout.size.bits();
                    if l.layout.abi.is_signed() {
                        // For signed ints the saturated value depends on the sign of the first
                        // term since the sign of the second term can be inferred from this and
                        // the fact that the operation has overflowed (if either is 0 no
                        // overflow can occur)
                        let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
                        let first_term_positive = first_term & (1 << (num_bits-1)) == 0;
                        if first_term_positive {
                            // Negative overflow not possible since the positive first term
                            // can only increase an (in range) negative term for addition
                            // or corresponding negated positive term for subtraction
                            Scalar::from_uint((1u128 << (num_bits - 1)) - 1,  // max positive
                                Size::from_bits(num_bits))
                        } else {
                            // Positive overflow not possible for similar reason
                            // max negative
                            Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
                        }
                    } else {  // unsigned
                        if is_add {
                            // max unsigned
                            Scalar::from_uint(u128::max_value() >> (128 - num_bits),
                                Size::from_bits(num_bits))
                        } else {  // underflow to 0
                            Scalar::from_uint(0u128, Size::from_bits(num_bits))
                        }
                    }
                } else {
                    val
                };
                self.write_scalar(val, dest)?;
            }
            "unchecked_shl" | "unchecked_shr" => {
                let l = self.read_immediate(args[0])?;
                let r = self.read_immediate(args[1])?;
                let bin_op = match intrinsic_name {
                    "unchecked_shl" => BinOp::Shl,
                    "unchecked_shr" => BinOp::Shr,
                    _ => bug!("Already checked for int ops")
                };
                let (val, overflowed) = self.binary_op(bin_op, l, r)?;
                if overflowed {
                    let layout = self.layout_of(substs.type_at(0))?;
                    let r_val =  r.to_scalar()?.to_bits(layout.size)?;
                    return err!(Intrinsic(
                        format!("Overflowing shift by {} in {}", r_val, intrinsic_name),
                    ));
                }
                self.write_scalar(val, dest)?;
            }
            "rotate_left" | "rotate_right" => {
                // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
                // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
                let layout = self.layout_of(substs.type_at(0))?;
                let val_bits = self.read_scalar(args[0])?.to_bits(layout.size)?;
                let raw_shift_bits = self.read_scalar(args[1])?.to_bits(layout.size)?;
                let width_bits = layout.size.bits() as u128;
                let shift_bits = raw_shift_bits % width_bits;
                let inv_shift_bits = (width_bits - raw_shift_bits) % width_bits;
                let result_bits = if intrinsic_name == "rotate_left" {
                    (val_bits << shift_bits) | (val_bits >> inv_shift_bits)
                } else {
                    (val_bits >> shift_bits) | (val_bits << inv_shift_bits)
                };
                let truncated_bits = self.truncate(result_bits, layout);
                let result = Scalar::from_uint(truncated_bits, layout.size);
                self.write_scalar(result, dest)?;
            }
            "transmute" => {
                self.copy_op_transmute(args[0], dest)?;
            }

            _ => return Ok(false),
        }

        Ok(true)
    }

    /// "Intercept" a function call because we have something special to do for it.
    /// Returns `true` if an intercept happened.
    pub fn hook_fn(
        &mut self,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, M::PointerTag>],
        dest: Option<PlaceTy<'tcx, M::PointerTag>>,
    ) -> EvalResult<'tcx, bool> {
        let def_id = instance.def_id();
        // Some fn calls are actually BinOp intrinsics
        if let Some((op, oflo)) = self.tcx.is_binop_lang_item(def_id) {
            let dest = dest.expect("128 lowerings can't diverge");
            let l = self.read_immediate(args[0])?;
            let r = self.read_immediate(args[1])?;
            if oflo {
                self.binop_with_overflow(op, l, r, dest)?;
            } else {
                self.binop_ignore_overflow(op, l, r, dest)?;
            }
            return Ok(true);
        } else if Some(def_id) == self.tcx.lang_items().panic_fn() {
            assert!(args.len() == 1);
            // &(&'static str, &'static str, u32, u32)
            let place = self.deref_operand(args[0])?;
            let (msg, file, line, col) = (
                self.mplace_field(place, 0)?,
                self.mplace_field(place, 1)?,
                self.mplace_field(place, 2)?,
                self.mplace_field(place, 3)?,
            );

            let msg_place = self.deref_operand(msg.into())?;
            let msg = Symbol::intern(self.read_str(msg_place)?);
            let file_place = self.deref_operand(file.into())?;
            let file = Symbol::intern(self.read_str(file_place)?);
            let line = self.read_scalar(line.into())?.to_u32()?;
            let col = self.read_scalar(col.into())?.to_u32()?;
            return Err(InterpError::Panic { msg, file, line, col }.into());
        } else if Some(def_id) == self.tcx.lang_items().begin_panic_fn() {
            assert!(args.len() == 2);
            // &'static str, &(&'static str, u32, u32)
            let msg = args[0];
            let place = self.deref_operand(args[1])?;
            let (file, line, col) = (
                self.mplace_field(place, 0)?,
                self.mplace_field(place, 1)?,
                self.mplace_field(place, 2)?,
            );

            let msg_place = self.deref_operand(msg.into())?;
            let msg = Symbol::intern(self.read_str(msg_place)?);
            let file_place = self.deref_operand(file.into())?;
            let file = Symbol::intern(self.read_str(file_place)?);
            let line = self.read_scalar(line.into())?.to_u32()?;
            let col = self.read_scalar(col.into())?.to_u32()?;
            return Err(InterpError::Panic { msg, file, line, col }.into());
        } else {
            return Ok(false);
        }
    }
}
<commit_msg>Re-add intrinsics.rs changes<commit_after>//! Intrinsics and other functions that the miri engine executes without
//! looking at their MIR. Intrinsics/functions supported here are shared by CTFE
//! and miri.

use syntax::symbol::Symbol;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, Primitive, Size};
use rustc::mir::BinOp;
use rustc::mir::interpret::{
    EvalResult, InterpError, Scalar,
};

use super::{
    Machine, PlaceTy, OpTy, InterpretCx,
};

mod type_name;

pub use type_name::*;

fn numeric_intrinsic<'tcx, Tag>(
    name: &str,
    bits: u128,
    kind: Primitive,
) -> EvalResult<'tcx, Scalar<Tag>> {
    let size = match kind {
        Primitive::Int(integer, _) => integer.size(),
        _ => bug!("invalid `{}` argument: {:?}", name, bits),
    };
    let extra = 128 - size.bits() as u128;
    let bits_out = match name {
        "ctpop" => bits.count_ones() as u128,
        "ctlz" => bits.leading_zeros() as u128 - extra,
        "cttz" => (bits << extra).trailing_zeros() as u128 - extra,
        "bswap" => (bits << extra).swap_bytes(),
        "bitreverse" => (bits << extra).reverse_bits(),
        _ => bug!("not a numeric intrinsic: {}", name),
    };
    Ok(Scalar::from_uint(bits_out, size))
}

impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
    /// Returns `true` if emulation happened.
    pub fn emulate_intrinsic(
        &mut self,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, M::PointerTag>],
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx, bool> {
        let substs = instance.substs;

        let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
        match intrinsic_name {
            "min_align_of" => {
                let elem_ty = substs.type_at(0);
                let elem_align = self.layout_of(elem_ty)?.align.abi.bytes();
                let align_val = Scalar::from_uint(elem_align, dest.layout.size);
                self.write_scalar(align_val, dest)?;
            }

            "needs_drop" => {
                let ty = substs.type_at(0);
                let ty_needs_drop = ty.needs_drop(self.tcx.tcx, self.param_env);
                let val = Scalar::from_bool(ty_needs_drop);
                self.write_scalar(val, dest)?;
            }

            "size_of" => {
                let ty = substs.type_at(0);
                let size = self.layout_of(ty)?.size.bytes() as u128;
                let size_val = Scalar::from_uint(size, dest.layout.size);
                self.write_scalar(size_val, dest)?;
            }

            "type_id" => {
                let ty = substs.type_at(0);
                let type_id = self.tcx.type_id_hash(ty) as u128;
                let id_val = Scalar::from_uint(type_id, dest.layout.size);
                self.write_scalar(id_val, dest)?;
            }

            "type_name" => {
                let alloc = alloc_type_name(self.tcx.tcx, substs.type_at(0));
                let name_id = self.tcx.alloc_map.lock().create_memory_alloc(alloc);
                let id_ptr = self.memory.tag_static_base_pointer(name_id.into());
                let alloc_len = alloc.bytes.len() as u64;
                let name_val = Immediate::new_slice(Scalar::Ptr(id_ptr), alloc_len, self);
                self.write_immediate(name_val, dest)?;
            }

            | "ctpop"
            | "cttz"
            | "cttz_nonzero"
            | "ctlz"
            | "ctlz_nonzero"
            | "bswap"
            | "bitreverse" => {
                let ty = substs.type_at(0);
                let layout_of = self.layout_of(ty)?;
                let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?;
                let kind = match layout_of.abi {
                    ty::layout::Abi::Scalar(ref scalar) => scalar.value,
                    _ => Err(::rustc::mir::interpret::InterpError::TypeNotPrimitive(ty))?,
                };
                let out_val = if intrinsic_name.ends_with("_nonzero") {
                    if bits == 0 {
                        return err!(Intrinsic(format!("{} called on 0", intrinsic_name)));
                    }
                    numeric_intrinsic(intrinsic_name.trim_end_matches("_nonzero"), bits, kind)?
                } else {
                    numeric_intrinsic(intrinsic_name, bits, kind)?
                };
                self.write_scalar(out_val, dest)?;
            }
            | "overflowing_add"
            | "overflowing_sub"
            | "overflowing_mul"
            | "add_with_overflow"
            | "sub_with_overflow"
            | "mul_with_overflow" => {
                let lhs = self.read_immediate(args[0])?;
                let rhs = self.read_immediate(args[1])?;
                let (bin_op, ignore_overflow) = match intrinsic_name {
                    "overflowing_add" => (BinOp::Add, true),
                    "overflowing_sub" => (BinOp::Sub, true),
                    "overflowing_mul" => (BinOp::Mul, true),
                    "add_with_overflow" => (BinOp::Add, false),
                    "sub_with_overflow" => (BinOp::Sub, false),
                    "mul_with_overflow" => (BinOp::Mul, false),
                    _ => bug!("Already checked for int ops")
                };
                if ignore_overflow {
                    self.binop_ignore_overflow(bin_op, lhs, rhs, dest)?;
                } else {
                    self.binop_with_overflow(bin_op, lhs, rhs, dest)?;
                }
            }
            "saturating_add" | "saturating_sub" => {
                let l = self.read_immediate(args[0])?;
                let r = self.read_immediate(args[1])?;
                let is_add = intrinsic_name == "saturating_add";
                let (val, overflowed) = self.binary_op(if is_add {
                    BinOp::Add
                } else {
                    BinOp::Sub
                }, l, r)?;
                let val = if overflowed {
                    let num_bits = l.layout.size.bits();
                    if l.layout.abi.is_signed() {
                        // For signed ints the saturated value depends on the sign of the first
                        // term since the sign of the second term can be inferred from this and
                        // the fact that the operation has overflowed (if either is 0 no
                        // overflow can occur)
                        let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
                        let first_term_positive = first_term & (1 << (num_bits-1)) == 0;
                        if first_term_positive {
                            // Negative overflow not possible since the positive first term
                            // can only increase an (in range) negative term for addition
                            // or corresponding negated positive term for subtraction
                            Scalar::from_uint((1u128 << (num_bits - 1)) - 1,  // max positive
                                Size::from_bits(num_bits))
                        } else {
                            // Positive overflow not possible for similar reason
                            // max negative
                            Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
                        }
                    } else {  // unsigned
                        if is_add {
                            // max unsigned
                            Scalar::from_uint(u128::max_value() >> (128 - num_bits),
                                Size::from_bits(num_bits))
                        } else {  // underflow to 0
                            Scalar::from_uint(0u128, Size::from_bits(num_bits))
                        }
                    }
                } else {
                    val
                };
                self.write_scalar(val, dest)?;
            }
            "unchecked_shl" | "unchecked_shr" => {
                let l = self.read_immediate(args[0])?;
                let r = self.read_immediate(args[1])?;
                let bin_op = match intrinsic_name {
                    "unchecked_shl" => BinOp::Shl,
                    "unchecked_shr" => BinOp::Shr,
                    _ => bug!("Already checked for int ops")
                };
                let (val, overflowed) = self.binary_op(bin_op, l, r)?;
                if overflowed {
                    let layout = self.layout_of(substs.type_at(0))?;
                    let r_val =  r.to_scalar()?.to_bits(layout.size)?;
                    return err!(Intrinsic(
                        format!("Overflowing shift by {} in {}", r_val, intrinsic_name),
                    ));
                }
                self.write_scalar(val, dest)?;
            }
            "rotate_left" | "rotate_right" => {
                // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
                // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
                let layout = self.layout_of(substs.type_at(0))?;
                let val_bits = self.read_scalar(args[0])?.to_bits(layout.size)?;
                let raw_shift_bits = self.read_scalar(args[1])?.to_bits(layout.size)?;
                let width_bits = layout.size.bits() as u128;
                let shift_bits = raw_shift_bits % width_bits;
                let inv_shift_bits = (width_bits - raw_shift_bits) % width_bits;
                let result_bits = if intrinsic_name == "rotate_left" {
                    (val_bits << shift_bits) | (val_bits >> inv_shift_bits)
                } else {
                    (val_bits >> shift_bits) | (val_bits << inv_shift_bits)
                };
                let truncated_bits = self.truncate(result_bits, layout);
                let result = Scalar::from_uint(truncated_bits, layout.size);
                self.write_scalar(result, dest)?;
            }
            "transmute" => {
                self.copy_op_transmute(args[0], dest)?;
            }

            _ => return Ok(false),
        }

        Ok(true)
    }

    /// "Intercept" a function call because we have something special to do for it.
    /// Returns `true` if an intercept happened.
    pub fn hook_fn(
        &mut self,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, M::PointerTag>],
        dest: Option<PlaceTy<'tcx, M::PointerTag>>,
    ) -> EvalResult<'tcx, bool> {
        let def_id = instance.def_id();
        // Some fn calls are actually BinOp intrinsics
        if let Some((op, oflo)) = self.tcx.is_binop_lang_item(def_id) {
            let dest = dest.expect("128 lowerings can't diverge");
            let l = self.read_immediate(args[0])?;
            let r = self.read_immediate(args[1])?;
            if oflo {
                self.binop_with_overflow(op, l, r, dest)?;
            } else {
                self.binop_ignore_overflow(op, l, r, dest)?;
            }
            return Ok(true);
        } else if Some(def_id) == self.tcx.lang_items().panic_fn() {
            assert!(args.len() == 1);
            // &(&'static str, &'static str, u32, u32)
            let place = self.deref_operand(args[0])?;
            let (msg, file, line, col) = (
                self.mplace_field(place, 0)?,
                self.mplace_field(place, 1)?,
                self.mplace_field(place, 2)?,
                self.mplace_field(place, 3)?,
            );

            let msg_place = self.deref_operand(msg.into())?;
            let msg = Symbol::intern(self.read_str(msg_place)?);
            let file_place = self.deref_operand(file.into())?;
            let file = Symbol::intern(self.read_str(file_place)?);
            let line = self.read_scalar(line.into())?.to_u32()?;
            let col = self.read_scalar(col.into())?.to_u32()?;
            return Err(InterpError::Panic { msg, file, line, col }.into());
        } else if Some(def_id) == self.tcx.lang_items().begin_panic_fn() {
            assert!(args.len() == 2);
            // &'static str, &(&'static str, u32, u32)
            let msg = args[0];
            let place = self.deref_operand(args[1])?;
            let (file, line, col) = (
                self.mplace_field(place, 0)?,
                self.mplace_field(place, 1)?,
                self.mplace_field(place, 2)?,
            );

            let msg_place = self.deref_operand(msg.into())?;
            let msg = Symbol::intern(self.read_str(msg_place)?);
            let file_place = self.deref_operand(file.into())?;
            let file = Symbol::intern(self.read_str(file_place)?);
            let line = self.read_scalar(line.into())?.to_u32()?;
            let col = self.read_scalar(col.into())?.to_u32()?;
            return Err(InterpError::Panic { msg, file, line, col }.into());
        } else {
            return Ok(false);
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use ::syn::Ident;
use ::quote::Tokens;
use ::yaml_rust::Yaml;

pub(super) fn infer_schema(name: &Ident, schema: &Yaml) -> Result<Tokens, Box<Error>> {
    Ok(quote! {
        extern crate tapioca;
        use tapioca::Schema;

        struct Resource;

        impl #name {
            fn resource() -> Resource {
                Resource
            }
        }

        impl Schema for #name {
            fn get(&self) {
                //!TODO: Replace for compile_error! macro
                //! when rust-lang/rust#40872 implemented
                panic!("GET not allowed for /")
            }
        }

        impl Schema for Resource {
            fn get(&self) {
                panic!("Not implemented!")
            }
        }
    })
}
<commit_msg>Check schema version before inference<commit_after>use std::error::Error;
use ::syn::Ident;
use ::quote::Tokens;
use ::yaml_rust::Yaml;

const SCHEMA_VERSION_KEY: &'static str = "openapi";

type TokensResult = Result<Tokens, Box<Error + Send + Sync>>;

pub(super) fn infer_schema(name: &Ident, schema: &Yaml) -> TokensResult {
    match schema[SCHEMA_VERSION_KEY].as_str() {
        None => Err(From::from("Unspecified schema version.")),
        Some("3.0.0") => infer_schema_v3(&name, &schema),
        Some(version) => Err(From::from(format!("Unsupported schema version: {}", version))),
    }
}

fn infer_schema_v3(name: &Ident, schema: &Yaml) -> TokensResult {
    Ok(quote! {
        extern crate tapioca;
        use tapioca::Schema;

        struct Resource;

        impl #name {
            fn resource() -> Resource {
                Resource
            }
        }

        impl Schema for #name {
            fn get(&self) {
                //!TODO: Replace for compile_error! macro
                //! when rust-lang/rust#40872 implemented
                panic!("GET not allowed for /")
            }
        }

        impl Schema for Resource {
            fn get(&self) {
                panic!("Not implemented!")
            }
        }
    })
}
<|endoftext|>


<commit_before><commit_msg>Run destructors on heap objects in-place.<commit_after><|endoftext|>


<commit_before>use std::str::FromStr;
use url::{self, Url};
use regex::Regex;
use errors::{self, Result};

/// Represents query from user.
///
/// Available patterns are:
///
/// * `<scheme>://[<username>[:<password>]@]<host>/<path-to-repo>.git`
///   - Available schemes are: `http[s]`, `ssh` and `git`.
/// * `<username>@<host>:<path-to-repo>`
///   - Equivalent to `ssh://<username>@<host>/<path-to-repo>.git`
/// * `<host>/<path-to-repo>`
pub enum Query {
  Url(url::Url),
  Path(Vec<String>),
}

impl Query {
  pub fn to_local_path(&self) -> Result<String> {
    let url = self.to_url()?;
    let mut path = url.host_str().map(ToOwned::to_owned).ok_or("url.host() is empty")?;
    path += url.path().trim_right_matches(".git");
    Ok(path)
  }

  pub fn to_url(&self) -> Result<url::Url> {
    match *self {
      Query::Url(ref url) => Ok(url.clone()),
      Query::Path(ref path) => {
        let host = path.iter().map(|s| s.as_str()).next().ok_or("empty host")?;
        match host {
          "github.com" | "bitbucket.org" | "gitlab.com" => {
            Url::parse(&format!("https://{}.git", path.join("/"))).map_err(Into::into)
          }
          _ => {
            Url::parse(&format!("https://github.com/{}.git", path.join("/"))).map_err(Into::into)
          }
        }
      }
    }
  }
}

impl FromStr for Query {
  type Err = errors::Error;

  fn from_str(s: &str) -> ::std::result::Result<Query, Self::Err> {
    let re_scheme = Regex::new(r"^([^:]+)://").unwrap();
    let re_scplike = Regex::new(r"^((?:[^@]+@)?)([^:]+):/?(.+)$").unwrap();

    if let Some(cap) = re_scheme.captures(s) {
      match cap.get(1).unwrap().as_str() {
        "http" | "https" | "ssh" | "git" => Ok(Query::Url(Url::parse(s)?)),
        scheme => Err(format!("'{}' is invalid scheme", scheme).into()),
      }

    } else if let Some(cap) = re_scplike.captures(s) {
      let username = cap.get(1)
        .and_then(|s| if s.as_str() != "" {
          Some(s.as_str())
        } else {
          None
        })
        .unwrap_or("git@");
      let host = cap.get(2).unwrap().as_str();
      let path = cap.get(3).unwrap().as_str();
      let url = Url::parse(&format!("ssh://{}{}/{}.git", username, host, path))?;
      Ok(Query::Url(url))

    } else {
      Ok(Query::Path(s.split("/").map(ToOwned::to_owned).collect()))
    }
  }
}

#[test]
fn test_https_pattern() {
  let s = "https://github.com/peco/peco.git";

  if let Ok(Query::Url(url)) = s.parse() {
    assert_eq!(url.scheme(), "https");
    assert_eq!(url.username(), "");
    assert_eq!(url.password(), None);
    assert_eq!(url.host_str(), Some("github.com"));
    assert_eq!(url.path(), "/peco/peco.git");
  } else {
    panic!("does not matches");
  }
}

#[test]
fn test_ssh_pattern() {
  let s = "ssh://gituser@github.com:2222/peco/peco.git";

  if let Ok(Query::Url(url)) = s.parse() {
    assert_eq!(url.scheme(), "ssh");
    assert_eq!(url.username(), "gituser");
    assert_eq!(url.password(), None);
    assert_eq!(url.host_str(), Some("github.com"));
    assert_eq!(url.port(), Some(2222));
    assert_eq!(url.path(), "/peco/peco.git");
  } else {
    panic!("does not matches");
  }
}

#[test]
fn test_scplike_pattern() {
  let s = "git@github.com:peco/peco";

  if let Ok(Query::Url(url)) = s.parse() {
    assert_eq!(url.scheme(), "ssh");
    assert_eq!(url.username(), "git");
    assert_eq!(url.password(), None);
    assert_eq!(url.host_str(), Some("github.com"));
    assert_eq!(url.path(), "/peco/peco.git");
  } else {
    panic!("does not matches");
  }
}

#[test]
fn test_short_pattern_with_host() {
  let s = "github.com/peco/peco";

  if let Ok(Query::Path(path)) = s.parse() {
    assert_eq!(path, ["github.com", "peco", "peco"]);
  } else {
    panic!("does not matches")
  }
}

#[test]
fn test_short_pattern_without_host() {
  let s = "peco/peco";

  if let Ok(Query::Path(path)) = s.parse() {
    assert_eq!(path, ["peco", "peco"]);
  } else {
    panic!("does not matches")
  }
}
<commit_msg>Accepts SCP-like patterns with suffix `.git`. (#2)<commit_after>use std::str::FromStr;
use url::{self, Url};
use regex::Regex;
use errors::{self, Result};

/// Represents query from user.
///
/// Available patterns are:
///
/// * `<scheme>://[<username>[:<password>]@]<host>/<path-to-repo>.git`
///   - Available schemes are: `http[s]`, `ssh` and `git`.
/// * `<username>@<host>:<path-to-repo>`
///   - Equivalent to `ssh://<username>@<host>/<path-to-repo>.git`
/// * `<host>/<path-to-repo>`
pub enum Query {
  Url(url::Url),
  Path(Vec<String>),
}

impl Query {
  pub fn to_local_path(&self) -> Result<String> {
    let url = self.to_url()?;
    let mut path = url.host_str().map(ToOwned::to_owned).ok_or("url.host() is empty")?;
    path += url.path().trim_right_matches(".git");
    Ok(path)
  }

  pub fn to_url(&self) -> Result<url::Url> {
    match *self {
      Query::Url(ref url) => Ok(url.clone()),
      Query::Path(ref path) => {
        let host = path.iter().map(|s| s.as_str()).next().ok_or("empty host")?;
        match host {
          "github.com" | "bitbucket.org" | "gitlab.com" => {
            Url::parse(&format!("https://{}.git", path.join("/"))).map_err(Into::into)
          }
          _ => {
            Url::parse(&format!("https://github.com/{}.git", path.join("/"))).map_err(Into::into)
          }
        }
      }
    }
  }
}

impl FromStr for Query {
  type Err = errors::Error;

  fn from_str(s: &str) -> ::std::result::Result<Query, Self::Err> {
    let re_scheme = Regex::new(r"^([^:]+)://").unwrap();
    let re_scplike = Regex::new(r"^((?:[^@]+@)?)([^:]+):/?(.+)$").unwrap();

    if let Some(cap) = re_scheme.captures(s) {
      match cap.get(1).unwrap().as_str() {
        "http" | "https" | "ssh" | "git" => Ok(Query::Url(Url::parse(s)?)),
        scheme => Err(format!("'{}' is invalid scheme", scheme).into()),
      }

    } else if let Some(cap) = re_scplike.captures(s) {
      let username = cap.get(1)
        .and_then(|s| if s.as_str() != "" {
          Some(s.as_str())
        } else {
          None
        })
        .unwrap_or("git@");
      let host = cap.get(2).unwrap().as_str();
      let path = cap.get(3).unwrap().as_str().trim_right_matches(".git");
      let url = Url::parse(&format!("ssh://{}{}/{}.git", username, host, path))?;
      Ok(Query::Url(url))

    } else {
      Ok(Query::Path(s.split("/").map(ToOwned::to_owned).collect()))
    }
  }
}

#[test]
fn test_https_pattern() {
  let s = "https://github.com/peco/peco.git";

  if let Ok(Query::Url(url)) = s.parse() {
    assert_eq!(url.scheme(), "https");
    assert_eq!(url.username(), "");
    assert_eq!(url.password(), None);
    assert_eq!(url.host_str(), Some("github.com"));
    assert_eq!(url.path(), "/peco/peco.git");
  } else {
    panic!("does not matches");
  }
}

#[test]
fn test_ssh_pattern() {
  let s = "ssh://gituser@github.com:2222/peco/peco.git";

  if let Ok(Query::Url(url)) = s.parse() {
    assert_eq!(url.scheme(), "ssh");
    assert_eq!(url.username(), "gituser");
    assert_eq!(url.password(), None);
    assert_eq!(url.host_str(), Some("github.com"));
    assert_eq!(url.port(), Some(2222));
    assert_eq!(url.path(), "/peco/peco.git");
  } else {
    panic!("does not matches");
  }
}

#[test]
fn test_scplike_pattern() {
  let ss = &["git@github.com:peco/peco.git", "git@github.com:peco/peco"];
  for s in ss {
    if let Ok(Query::Url(url)) = s.parse() {
      assert_eq!(url.scheme(), "ssh");
      assert_eq!(url.username(), "git");
      assert_eq!(url.password(), None);
      assert_eq!(url.host_str(), Some("github.com"));
      assert_eq!(url.path(), "/peco/peco.git");
    } else {
      panic!("does not matches");
    }
  }
}

#[test]
fn test_short_pattern_with_host() {
  let s = "github.com/peco/peco";

  if let Ok(Query::Path(path)) = s.parse() {
    assert_eq!(path, ["github.com", "peco", "peco"]);
  } else {
    panic!("does not matches")
  }
}

#[test]
fn test_short_pattern_without_host() {
  let s = "peco/peco";

  if let Ok(Query::Path(path)) = s.parse() {
    assert_eq!(path, ["peco", "peco"]);
  } else {
    panic!("does not matches")
  }
}
<|endoftext|>


<commit_before>// An item is line of text that read from `find` command or stdin together with
// the internal states, such as selected or not

use ansi::ANSIParser;
use curses::attr_t;
use field::*;
use regex::Regex;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::default::Default;
use std::sync::Arc;

// An item will store everything that one line input will need to be operated and displayed.
//
// What's special about an item?
// The simplest version of an item is a line of string, but things are getting more complex:
// - The conversion of lower/upper case is slow in rust, because it involds unicode.
// - We may need to interpret the ANSI codes in the text.
// - The text can be transformed and limited while searching.

// About the ANSI, we made assumption that it is linewise, that means no ANSI codes will affect
// more than one line.

#[derive(Debug)]
pub struct Item {
    // (num of run, number of index)
    index: (usize, usize),

    // The text that will be ouptut when user press `enter`
    output_text: String,

    // The text that will shown into the screen. Can be transformed.
    text: String,

    // cache of the lower case version of text. To improve speed
    chars: Vec<char>,

    // the ansi state (color) of the text
    ansi_states: Vec<(usize, attr_t)>,
    matching_ranges: Vec<(usize, usize)>,

    // For the transformed ANSI case, the output will need another transform.
    using_transform_fields: bool,
    ansi_enabled: bool,
}

impl<'a> Item {
    pub fn new(
        orig_text: String,
        ansi_enabled: bool,
        trans_fields: &[FieldRange],
        matching_fields: &[FieldRange],
        delimiter: &Regex,
        index: (usize, usize),
    ) -> Self {
        let using_transform_fields = !trans_fields.is_empty();

        //        transformed | ANSI             | output
        //------------------------------------------------------
        //                    +- T -> trans+ANSI | ANSI
        //                    |                  |
        //      +- T -> trans +- F -> trans      | orig
        // orig |                                |
        //      +- F -> orig  +- T -> ANSI     ==| ANSI
        //                    |                  |
        //                    +- F -> orig       | orig

        let mut ansi_parser: ANSIParser = Default::default();

        let (text, states_text) = if using_transform_fields && ansi_enabled {
            // ansi and transform
            ansi_parser.parse_ansi(&parse_transform_fields(delimiter, &orig_text, trans_fields))
        } else if using_transform_fields {
            // transformed, not ansi
            (parse_transform_fields(delimiter, &orig_text, trans_fields), Vec::new())
        } else if ansi_enabled {
            // not transformed, ansi
            ansi_parser.parse_ansi(&orig_text)
        } else {
            // normal case
            ("".to_string(), Vec::new())
        };

        let mut ret = Item {
            index: index,
            output_text: orig_text,
            text: text,
            chars: Vec::new(),
            ansi_states: states_text,
            using_transform_fields: !trans_fields.is_empty(),
            matching_ranges: Vec::new(),
            ansi_enabled: ansi_enabled,
        };

        let lower_chars: Vec<char> = ret.get_text().chars().collect();
        let matching_ranges = if !matching_fields.is_empty() {
            parse_matching_fields(delimiter, ret.get_text(), matching_fields)
        } else {
            vec![(0, lower_chars.len())]
        };

        ret.chars = lower_chars;
        ret.matching_ranges = matching_ranges;
        ret
    }

    pub fn get_text(&self) -> &str {
        if !self.using_transform_fields && !self.ansi_enabled {
            &self.output_text
        } else {
            &self.text
        }
    }

    pub fn get_output_text(&'a self) -> Cow<'a, str> {
        if self.using_transform_fields && self.ansi_enabled {
            let mut ansi_parser: ANSIParser = Default::default();
            let (text, _) = ansi_parser.parse_ansi(&self.output_text);
            Cow::Owned(text)
        } else if !self.using_transform_fields && self.ansi_enabled {
            Cow::Borrowed(&self.text)
        } else {
            Cow::Borrowed(&self.output_text)
        }
    }

    pub fn get_chars(&self) -> &[char] {
        &self.chars
    }

    pub fn get_ansi_states(&self) -> &Vec<(usize, attr_t)> {
        &self.ansi_states
    }

    pub fn get_index(&self) -> usize {
        self.index.1
    }

    pub fn get_full_index(&self) -> (usize, usize) {
        self.index
    }

    pub fn get_matching_ranges(&self) -> &[(usize, usize)] {
        &self.matching_ranges
    }
}

impl Clone for Item {
    fn clone(&self) -> Item {
        Item {
            index: self.index,
            output_text: self.output_text.clone(),
            text: self.text.clone(),
            chars: self.chars.clone(),
            ansi_states: self.ansi_states.clone(),
            using_transform_fields: self.using_transform_fields,
            matching_ranges: self.matching_ranges.clone(),
            ansi_enabled: self.ansi_enabled,
        }
    }
}

// A bunch of items
pub type ItemGroup = Vec<Arc<Item>>;
pub type MatchedItemGroup = Vec<MatchedItem>;

pub type Rank = [i64; 4]; // score, index, start, end

#[derive(PartialEq, Eq, Clone, Debug)]
#[allow(dead_code)]
pub enum MatchedRange {
    Range(usize, usize),
    Chars(Vec<usize>),
}

#[derive(Clone, Debug)]
pub struct MatchedItem {
    pub item: Arc<Item>,
    pub rank: Rank,
    pub matched_range: Option<MatchedRange>, // range of chars that metched the pattern
}

impl MatchedItem {
    pub fn builder(item: Arc<Item>) -> Self {
        MatchedItem {
            item: item,
            rank: [0, 0, 0, 0],
            matched_range: None,
        }
    }

    pub fn matched_range(mut self, range: MatchedRange) -> Self {
        self.matched_range = Some(range);
        self
    }

    pub fn rank(mut self, rank: Rank) -> Self {
        self.rank = rank;
        self
    }

    pub fn build(self) -> Self {
        self
    }
}

impl Ord for MatchedItem {
    fn cmp(&self, other: &MatchedItem) -> Ordering {
        self.rank.cmp(&other.rank)
    }
}

// `PartialOrd` needs to be implemented as well.
impl PartialOrd for MatchedItem {
    fn partial_cmp(&self, other: &MatchedItem) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for MatchedItem {
    fn eq(&self, other: &MatchedItem) -> bool {
        self.rank == other.rank
    }
}

impl Eq for MatchedItem {}
<commit_msg>[item] optimize the creation of chars for ascii<commit_after>// An item is line of text that read from `find` command or stdin together with
// the internal states, such as selected or not

use ansi::ANSIParser;
use curses::attr_t;
use field::*;
use regex::Regex;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::default::Default;
use std::sync::Arc;

// An item will store everything that one line input will need to be operated and displayed.
//
// What's special about an item?
// The simplest version of an item is a line of string, but things are getting more complex:
// - The conversion of lower/upper case is slow in rust, because it involds unicode.
// - We may need to interpret the ANSI codes in the text.
// - The text can be transformed and limited while searching.

// About the ANSI, we made assumption that it is linewise, that means no ANSI codes will affect
// more than one line.

#[derive(Debug)]
pub struct Item {
    // (num of run, number of index)
    index: (usize, usize),

    // The text that will be ouptut when user press `enter`
    output_text: String,

    // The text that will shown into the screen. Can be transformed.
    text: String,

    // cache of the lower case version of text. To improve speed
    chars: Vec<char>,

    // the ansi state (color) of the text
    ansi_states: Vec<(usize, attr_t)>,
    matching_ranges: Vec<(usize, usize)>,

    // For the transformed ANSI case, the output will need another transform.
    using_transform_fields: bool,
    ansi_enabled: bool,
}

impl<'a> Item {
    pub fn new(
        orig_text: String,
        ansi_enabled: bool,
        trans_fields: &[FieldRange],
        matching_fields: &[FieldRange],
        delimiter: &Regex,
        index: (usize, usize),
    ) -> Self {
        let using_transform_fields = !trans_fields.is_empty();

        //        transformed | ANSI             | output
        //------------------------------------------------------
        //                    +- T -> trans+ANSI | ANSI
        //                    |                  |
        //      +- T -> trans +- F -> trans      | orig
        // orig |                                |
        //      +- F -> orig  +- T -> ANSI     ==| ANSI
        //                    |                  |
        //                    +- F -> orig       | orig

        let mut ansi_parser: ANSIParser = Default::default();

        let (text, states_text) = if using_transform_fields && ansi_enabled {
            // ansi and transform
            ansi_parser.parse_ansi(&parse_transform_fields(delimiter, &orig_text, trans_fields))
        } else if using_transform_fields {
            // transformed, not ansi
            (parse_transform_fields(delimiter, &orig_text, trans_fields), Vec::new())
        } else if ansi_enabled {
            // not transformed, ansi
            ansi_parser.parse_ansi(&orig_text)
        } else {
            // normal case
            ("".to_string(), Vec::new())
        };

        let mut ret = Item {
            index: index,
            output_text: orig_text,
            text: text,
            chars: Vec::new(),
            ansi_states: states_text,
            using_transform_fields: !trans_fields.is_empty(),
            matching_ranges: Vec::new(),
            ansi_enabled: ansi_enabled,
        };

        let chars: Vec<char> = if ret.get_text().as_bytes().is_ascii() {
            ret.get_text().as_bytes().iter().map(|&s| s as char).collect()
        } else {
            ret.get_text().chars().collect()
        };

        let matching_ranges = if !matching_fields.is_empty() {
            parse_matching_fields(delimiter, ret.get_text(), matching_fields)
        } else {
            vec![(0, chars.len())]
        };

        ret.chars = chars;
        ret.matching_ranges = matching_ranges;
        ret
    }

    pub fn get_text(&self) -> &str {
        if !self.using_transform_fields && !self.ansi_enabled {
            &self.output_text
        } else {
            &self.text
        }
    }

    pub fn get_output_text(&'a self) -> Cow<'a, str> {
        if self.using_transform_fields && self.ansi_enabled {
            let mut ansi_parser: ANSIParser = Default::default();
            let (text, _) = ansi_parser.parse_ansi(&self.output_text);
            Cow::Owned(text)
        } else if !self.using_transform_fields && self.ansi_enabled {
            Cow::Borrowed(&self.text)
        } else {
            Cow::Borrowed(&self.output_text)
        }
    }

    pub fn get_chars(&self) -> &[char] {
        &self.chars
    }

    pub fn get_ansi_states(&self) -> &Vec<(usize, attr_t)> {
        &self.ansi_states
    }

    pub fn get_index(&self) -> usize {
        self.index.1
    }

    pub fn get_full_index(&self) -> (usize, usize) {
        self.index
    }

    pub fn get_matching_ranges(&self) -> &[(usize, usize)] {
        &self.matching_ranges
    }
}

impl Clone for Item {
    fn clone(&self) -> Item {
        Item {
            index: self.index,
            output_text: self.output_text.clone(),
            text: self.text.clone(),
            chars: self.chars.clone(),
            ansi_states: self.ansi_states.clone(),
            using_transform_fields: self.using_transform_fields,
            matching_ranges: self.matching_ranges.clone(),
            ansi_enabled: self.ansi_enabled,
        }
    }
}

// A bunch of items
pub type ItemGroup = Vec<Arc<Item>>;
pub type MatchedItemGroup = Vec<MatchedItem>;

pub type Rank = [i64; 4]; // score, index, start, end

#[derive(PartialEq, Eq, Clone, Debug)]
#[allow(dead_code)]
pub enum MatchedRange {
    Range(usize, usize),
    Chars(Vec<usize>),
}

#[derive(Clone, Debug)]
pub struct MatchedItem {
    pub item: Arc<Item>,
    pub rank: Rank,
    pub matched_range: Option<MatchedRange>, // range of chars that metched the pattern
}

impl MatchedItem {
    pub fn builder(item: Arc<Item>) -> Self {
        MatchedItem {
            item: item,
            rank: [0, 0, 0, 0],
            matched_range: None,
        }
    }

    pub fn matched_range(mut self, range: MatchedRange) -> Self {
        self.matched_range = Some(range);
        self
    }

    pub fn rank(mut self, rank: Rank) -> Self {
        self.rank = rank;
        self
    }

    pub fn build(self) -> Self {
        self
    }
}

impl Ord for MatchedItem {
    fn cmp(&self, other: &MatchedItem) -> Ordering {
        self.rank.cmp(&other.rank)
    }
}

// `PartialOrd` needs to be implemented as well.
impl PartialOrd for MatchedItem {
    fn partial_cmp(&self, other: &MatchedItem) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for MatchedItem {
    fn eq(&self, other: &MatchedItem) -> bool {
        self.rank == other.rank
    }
}

impl Eq for MatchedItem {}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

use config::Config;
use error::{Error, Result};
use std::path::PathBuf;

#[derive(Debug)]
#[derive(RustcDecodable, RustcEncodable)]
pub struct AgentConf {
    pub server_cert: String,
    pub users_path: String,
    pub api_port: i32,
    pub upload_port: i32,
    pub download_port: i32,
}

impl AgentConf {
    pub fn load_path(paths: Option<&[&str]>) -> Result<AgentConf> {
        let default_paths = ["/usr/local/etc", "/etc"];
        let paths = paths.unwrap_or(&default_paths);

        for p in paths.iter() {
            let mut path = PathBuf::from(p);
            path.push("intecture");
            path.push("agent.json");

            match Self::load(&path) {
                Ok(conf) => return Ok(conf),
                Err(_) => continue,
            }
        }

        Err(Error::MissingConf)
    }
}

impl Config for AgentConf {
    type ConfigFile = AgentConf;
}

#[cfg(test)]
mod tests {
    use config::Config;
    use czmq::zsys_init;
    use std::fs::create_dir;
    use super::*;
    use tempdir::TempDir;

    #[test]
    fn test_load_agent_conf() {
        zsys_init();

        let dir = TempDir::new("test_load_agent_conf").unwrap();

        assert!(AgentConf::load_path(None).is_err());

        let conf = AgentConf {
            server_cert: "/path/to/cert.crt".to_string(),
            users_path: "/path/to/users/certs".to_string(),
            api_port: 1,
            upload_port: 2,
            download_port: 3,
        };

        let mut dir_pathbuf = dir.path().to_path_buf();
        dir_pathbuf.push("intecture");
        create_dir(&dir_pathbuf).unwrap();

        dir_pathbuf.push("agent.json");
        AgentConf::save(&conf, dir_pathbuf.as_path()).unwrap();

        assert!(AgentConf::load_path(Some(&[dir.path().to_str().unwrap()])).is_ok());
    }
}
<commit_msg>Fix test<commit_after>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

use config::Config;
use error::{Error, Result};
use std::path::PathBuf;

#[derive(Debug)]
#[derive(RustcDecodable, RustcEncodable)]
pub struct AgentConf {
    pub server_cert: String,
    pub users_path: String,
    pub api_port: i32,
    pub upload_port: i32,
    pub download_port: i32,
}

impl AgentConf {
    pub fn load_path(paths: Option<&[&str]>) -> Result<AgentConf> {
        let default_paths = ["/usr/local/etc", "/etc"];
        let paths = paths.unwrap_or(&default_paths);

        for p in paths.iter() {
            let mut path = PathBuf::from(p);
            path.push("intecture");
            path.push("agent.json");

            match Self::load(&path) {
                Ok(conf) => return Ok(conf),
                Err(_) => continue,
            }
        }

        Err(Error::MissingConf)
    }
}

impl Config for AgentConf {
    type ConfigFile = AgentConf;
}

#[cfg(test)]
mod tests {
    use config::Config;
    use czmq::zsys_init;
    use std::fs::create_dir;
    use super::*;
    use tempdir::TempDir;

    #[test]
    fn test_load_agent_conf() {
        zsys_init();

        let dir = TempDir::new("test_load_agent_conf").unwrap();

        assert!(AgentConf::load_path(Some(&["/fake/dir"])).is_err());

        let conf = AgentConf {
            server_cert: "/path/to/cert.crt".to_string(),
            users_path: "/path/to/users/certs".to_string(),
            api_port: 1,
            upload_port: 2,
            download_port: 3,
        };

        let mut dir_pathbuf = dir.path().to_path_buf();
        dir_pathbuf.push("intecture");
        create_dir(&dir_pathbuf).unwrap();

        dir_pathbuf.push("agent.json");
        AgentConf::save(&conf, dir_pathbuf.as_path()).unwrap();

        assert!(AgentConf::load_path(Some(&[dir.path().to_str().unwrap()])).is_ok());
    }
}
<|endoftext|>


<commit_before>use regex_syntax::Expr;
use regex_syntax::Repeater;

use nfa::NFA;
use nfa::Spec;
use nfa::NFABuilder;
use nfa::Label;

struct Rule {
    regex: Expr,
    action: String,
}

/// Converts a sequence of characters into a concatenation of simple
/// transitions.
///
/// The return value is a Spec containing the concatenation of all
/// single transition automata generated for each character in `chars`.
fn literal_to_spec(chars: &Vec<char>) -> Spec {
    // take the first
    let mut tmp: Box<Spec> = Spec::single(Label::Symbol((*chars)[0]));

    // iterate for the others
    for i in chars.iter().skip(1) {
        let aux = Spec::single(Label::Symbol(*i));
        tmp = Spec::concat(tmp,aux);
    }

    // return the concatenation
    *tmp
}

/// Converts `re` and repeater specification `r` into a NFA `Spec`.
///
/// The repetition behavior is translated to the basic constructs
/// of a NFA `Spec`: union, concatenation and Kleene star of NFAs,
/// using the NFA built for `re` as one of the operands.
fn repeater_to_spec(re: &Expr, r: &Repeater) -> Spec {
    let s1 = Box::new(regex_to_nfa_spec(re));

    match *r {
        Repeater::ZeroOrOne => Spec::Union(Spec::single(Label::Epsilon), s1),
        Repeater::ZeroOrMore => Spec::Star(s1),
        Repeater::OneOrMore => Spec::Concat(s1.clone(), Spec::star(s1)),
        Repeater::Range { min, max } => unimplemented!()
    }
}

/// Converts the regexp `re` into a NFA `Spec`.
///
/// The function traverses the `re` syntax tree recursively, building
/// NFA Specs for each component and combining them according to the
/// operations in the ER.
pub fn regex_to_nfa_spec(re: &Expr) -> Spec {
    match *re {
        Expr::AnyChar => Spec::Single(Label::Any),
        Expr::AnyCharNoNL => Spec::Single(Label::Any),  // FIX: don't match newline
        Expr::Repeat { ref e, r, greedy } => repeater_to_spec(&*e, &r),
        Expr::Literal{ ref chars, casei} => literal_to_spec(chars),
        _ => unimplemented!()
    }
}

#[test]
fn test_repeater_zero_or_more1() {
    let re = Expr::parse(r".*").unwrap();
    let spec = regex_to_nfa_spec(&re);

    println!("regex: {:?}", re);
    assert_eq!(spec, *Spec::star(Spec::single(Label::Any)));

}

#[test]
fn test_literal() {
    let re = Expr::parse(r"ab").unwrap();
    let spec = regex_to_nfa_spec(&re);

    println!("regex: {:?}", re);
    assert_eq!(spec, *Spec::concat(Spec::single(Label::Symbol('a')), Spec::single(Label::Symbol('b'))));
}
<commit_msg>Conversion ER>NFA |Concat and Alternate done and tested<commit_after>use regex_syntax::Expr;
use regex_syntax::Repeater;

use nfa::NFA;
use nfa::Spec;
use nfa::NFABuilder;
use nfa::Label;

struct Rule {
    regex: Expr,
    action: String,
}

/// Converts a sequence of characters into a concatenation of simple
/// transitions.
///
/// The return value is a Spec containing the concatenation of all
/// single transition automata generated for each character in `chars`.
fn literal_to_spec(chars: &Vec<char>) -> Spec {
    // take the first
    let mut tmp: Box<Spec> = Spec::single(Label::Symbol((*chars)[0]));

    // iterate for the others
    for i in chars.iter().skip(1) {
        let aux = Spec::single(Label::Symbol(*i));
        tmp = Spec::concat(tmp,aux);
    }

    // return the concatenation
    *tmp
}

/// Converts a vector of Expr into a concatenation of Specs.
///
/// The return value is a Spec containing the concatenation of all
/// Expr in the parameter vector.
fn concat_to_spec(exprs: &Vec<Expr>) -> Spec {
    let mut tmp: Box<Spec> = Box::new(regex_to_nfa_spec(&(exprs[0])));

    for i in exprs.iter().skip(1) {
        let aux : Box<Spec> = Box::new(regex_to_nfa_spec(&i));
        tmp  = Spec::concat(tmp,aux);
    }

    *tmp
}

/// Converts a vector of Expr into a union of Specs.
///
/// The return value is a Spec containing the union of all
/// Expr in the parameter vector.
fn alternate_to_spec(exprs: &Vec<Expr>) -> Spec {
    let mut tmp: Box<Spec> = Box::new(regex_to_nfa_spec(&(exprs[0])));;

    for i in exprs.iter().skip(1) {
        let aux : Box<Spec> = Box::new(regex_to_nfa_spec(&i));
        tmp  = Spec::union(tmp,aux);
    }

    *tmp
}

/// Converts `re` and repeater specification `r` into a NFA `Spec`.
///
/// The repetition behavior is translated to the basic constructs
/// of a NFA `Spec`: union, concatenation and Kleene star of NFAs,
/// using the NFA built for `re` as one of the operands.
fn repeater_to_spec(re: &Expr, r: &Repeater) -> Spec {
    let s1 = Box::new(regex_to_nfa_spec(re));

    match *r {
        Repeater::ZeroOrOne => Spec::Union(Spec::single(Label::Epsilon), s1),
        Repeater::ZeroOrMore => Spec::Star(s1),
        Repeater::OneOrMore => Spec::Concat(s1.clone(), Spec::star(s1)),
        Repeater::Range { min, max } => unimplemented!()
    }
}

/// Converts the regexp `re` into a NFA `Spec`.
///
/// The function traverses the `re` syntax tree recursively, building
/// NFA Specs for each component and combining them according to the
/// operations in the ER.
pub fn regex_to_nfa_spec(re: &Expr) -> Spec {
    match *re {
        Expr::AnyChar => Spec::Single(Label::Any),
        Expr::AnyCharNoNL => Spec::Single(Label::Any),  // FIX: don't match newline
        Expr::Repeat { ref e, r, greedy } => repeater_to_spec(&*e, &r),
        Expr::Literal{ ref chars, casei} => literal_to_spec(chars),
        Expr::Concat(ref exprs) => concat_to_spec(&exprs),
        Expr::Alternate(ref exprs) => alternate_to_spec(&exprs),
        _ => unimplemented!()
    }
}

#[test]
fn test_repeater_zero_or_more1() {
    let re = Expr::parse(r".*").unwrap();
    let spec = regex_to_nfa_spec(&re);

    println!("regex: {:?}", re);
    assert_eq!(spec, *Spec::star(Spec::single(Label::Any)));

}

#[test]
fn test_literal() {
    let re = Expr::parse(r"ab").unwrap();
    let spec = regex_to_nfa_spec(&re);

    println!("regex: {:?}", re);
    assert_eq!(spec, *Spec::concat(Spec::single(Label::Symbol('a')), Spec::single(Label::Symbol('b'))));
}

#[test]
fn test_concat(){
    let re1 = Expr::parse(r"ab").unwrap();
    let re2 = Expr::parse(r"cd").unwrap();

    let mut tmp: Vec<Expr> = Vec::with_capacity(2);

    tmp.push(re1);
    tmp.push(re2);

    let aux = concat_to_spec(&tmp);

    let aux2 = NFABuilder::build_from_spec(aux);

    assert!(aux2.simulate("abcd"));
    assert!(!aux2.simulate("ab"));
    assert!(!aux2.simulate("cd"));

}

#[test]
fn test_altenate(){
    let re1 = Expr::parse(r"ab").unwrap();
    let re2 = Expr::parse(r"cd").unwrap();

    let mut tmp: Vec<Expr> = Vec::with_capacity(2);

    tmp.push(re1);
    tmp.push(re2);
    let aux = alternate_to_spec(&tmp);

    let aux2 = NFABuilder::build_from_spec(aux);

    assert!(!aux2.simulate("abcd"));
    assert!(aux2.simulate("ab"));
    assert!(aux2.simulate("cd"));
}

<|endoftext|>


<commit_before>// Copyright 2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use glib::translate::*;

#[derive(Clone, Debug)]
pub struct EventButton(::Event);

event_wrapper!(EventButton, GdkEventButton);
event_subtype!(EventButton, ButtonPress | _2buttonPress | _3buttonPress | ButtonRelease);
<commit_msg>Fix EventType variants<commit_after>// Copyright 2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use glib::translate::*;

#[derive(Clone, Debug)]
pub struct EventButton(::Event);

event_wrapper!(EventButton, GdkEventButton);
event_subtype!(EventButton, ButtonPress | DoubleButtonPress | TripleButtonPress | ButtonRelease);
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 dinowernli
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use std::f64;

use bitstring::Bit;
use bitstring::Bitstring;

// Open questions:
// - How to declare some fields final
// - How to declare some fields mutable (can be changed for non-mut self)
// - Have the tree implement iter and simplify some methods with "fold".

/// An object capable of predicting observations and rewards based on
/// experience. Predictors have an abstract notion of history which
/// grows over time and represents the experience.
pub trait Predictor {
  /// Returns the size of the currently tracked history.
  fn history_size(&self) -> usize;

  /// Appends the provided bit string to the tracked history.
  fn update(&mut self, bitstring: &Bitstring);

  /// Reverts the context tree to a previous state by undoing update
  /// operations. The specified size must be at most the current size.
  fn revert_to_history_size(&mut self, target_size: usize);

  /// Returns the probability, given the current history, that "bits" is the
  /// next symbol.
  fn predict(&mut self, bits: &Bitstring) -> f64;
}

/// Context tree which computes a probability estimate for a sequence of
/// bits based on a mixture model of Markov chains. Lower-degree Markov
/// chains have higher priors in the mixture model, thus formalizing the
/// notion of Occam's Razor.
///
/// In order to get a probability for a sequence, all bits in the sequence
/// must be processed in-order.
pub struct ContextTree {
  root: Node,
  history: Bitstring,
  depth: usize,
}

impl Predictor for ContextTree {
  fn history_size(&self) -> usize {
    self.history.len()
  }

  fn revert_to_history_size(&mut self, target_size: usize) {
    assert!(target_size <= self.history_size());
    while target_size > self.history_size() {
      self.revert_last();
    }
  }

  fn update(&mut self, bitstring: &Bitstring) {
    for bit in bitstring.bits() {
      self.update_bit(*bit);
    }
  }

  fn predict(&mut self, bits: &Bitstring) -> f64 {
    // If we don't have enough history, assume a uniform distribution.
    if !self.has_context() {
      let neg_len = -(bits.len() as i64);
      return (neg_len as f64).exp2();
    }

    // Add all the symbols and store the block probability before and after.
    let initial_size = self.history_size();
    let initial_log_prob = self.log_block_prob();

    self.update(bits);
    let final_log_prob = self.log_block_prob();
    self.revert_to_history_size(initial_size);

    // Let "b" be bits and "h" be our history. We use the equation:
    //      P[hb] = P[h] * P[b | h]
    // <==> log(P[hb]) = log(P[h]) + log(P[b | h])
    // <==> log(P[b | h]) = log(P[hb]) - log(P[h])
    let log_conditional_prob = final_log_prob - initial_log_prob;
    return log_conditional_prob.exp2();
  }
}

impl ContextTree {
  /// The depth of the tree is the distance between leaves and the root.
  /// For a given depth d, the tree will compute a mixture model of all
  /// Markov chains of degree at most d.
  pub fn create(depth: usize) -> Self {
    ContextTree {
      root: Node::create_root(depth, 0),
      history: Bitstring::new(),
      depth: depth,
    }
  }

  /// Returns the total number of nodes in the tree.
  pub fn size(&self) -> usize {
    self.root.size()
  }

  /// Adds a single bit to the history seen by this tree, updating all the
  /// involved nodes if necessary.
  fn update_bit(&mut self, bit: Bit) {
    self.for_node_in_context(&|node: &mut Node| {
      node.update(bit);
    });
    self.history.push(bit);
  }

  /// Removes a single bit from the history seen by this tree, updating all the
  /// involved nodes if necessary.
  fn revert_last(&mut self) {
    let bit = self.history.pop();
    self.for_node_in_context(&|node: &mut Node| {
      node.revert(bit);
    });
  }

  /// Returns log2 of the estimated probability of the current history.
  fn log_block_prob(&mut self) -> f64 {
    return self.root.log_weighted_prob();
  }

  /// Executes the provided closure on the current context, i.e., follows the
  /// current history down to a leaf and executes the closure on every node
  /// from the leaf to the root. Does nothing if the current history is not
  /// long enough to reach a leaf.
  fn for_node_in_context<F: Fn(&mut Node)>(&mut self, closure: &F) {
    if !self.has_context() {
      return;
    }
    self.root.execute(closure, &self.history, 0);
  }

  /// Inidicates whether this tree "has context", i.e., whether or not the
  /// history is long enough to be able to follow a path down to a leaf.
  fn has_context(&self) -> bool { self.history_size() >= self.depth }
}

/// One node in the context tree. Maintains a count of the number
/// of zeroes and ones seen and provides access to partial results
/// of the overall probability estimates computed in the context
/// tree.
struct Node {
  /// Children.
  zero_child: Option<Box<Node>>,
  one_child: Option<Box<Node>>,

  /// Frequencies.
  zeroes: u64,
  ones: u64,

  /// The log2 of the probability of a sequence with self.zeroes zeroes
  /// and self.ones one. Computed using the Krichevsky Trofimov
  /// estimator algorithm.
  log_kt_prob: f64,

  /// The log2 of the weighted block probability of the current sequence.
  /// Funtion of self.zeroes and self.ones and the values recursively
  /// provided by the children of this node (if any), lazily recomputed.
  log_weighted_prob: f64,
}

impl Node {
  /// Creates a node and all its children recursively until the provided
  /// depth is reached.
  pub fn create_root(target_depth: usize, current_depth: usize) -> Self {
    if target_depth == current_depth {
      return Node::new(None, None);  // Leaf.
    } else {
      return Node::new(
          Some(Box::new(Node::create_root(target_depth, current_depth + 1))),
          Some(Box::new(Node::create_root(target_depth, current_depth + 1))));
    }
  }

  fn new(zero_child: Option<Box<Node>>, one_child: Option<Box<Node>>) -> Self {
    // Context trees are complete trees (either both children or no children).
    assert!(zero_child.is_none() == one_child.is_none());

    return Node {
      zero_child: zero_child,
      one_child: one_child,
      zeroes: 0,
      ones: 0,
      log_kt_prob: 0.0,
      log_weighted_prob: 0.0,
    };
  }

  pub fn log_weighted_prob(&self) -> f64 {
    self.log_weighted_prob
  }

  /// Executes the given closure on the appropriate child (if any) and then on
  /// itself.
  pub fn execute<F: Fn(&mut Node)>(
      &mut self,
      closure: &F,
      history: &Bitstring,
      depth: usize) {
    if !self.is_leaf() {
      let bit = history.bit(history.len() - depth - 1);
      self.mut_child(bit).execute(closure, history, depth + 1);
    }
    closure(self);
  }

  /// Updates the state of the node based on the value of the new bit.
  /// Assumes that child nodes (if any) have already been updated.
  pub fn update(&mut self, bit: Bit) {
    *self.mut_frequency(bit) += 1;

    // Old value + 0.5 is the same as new value - 0.5.
    let first_summand = (*self.mut_frequency(bit) as f64 - 0.5).log2();
    let norm_summand = ((self.zeroes + self.ones) as f64).log2();

    self.log_kt_prob = first_summand - norm_summand + self.log_kt_prob;
    self.update_weighted_prob();
  }

  /// Corresponds to undoing one update for the specified bit value.
  /// Assumes that child nodes (if any) have already been reverted.
  pub fn revert(&mut self, bit: Bit) {
    *self.mut_frequency(bit) -= 1;
    // TODO(dinowernli): Update kt probs.
    self.update_weighted_prob();
  }

  /// Returns the child corresponding to the supplied bit. Must not be called
  /// on leaf nodes.
  fn mut_child(&mut self, bit: Bit) -> &mut Node {
    assert!(!self.is_leaf());
    match bit {
      Bit::Zero => self.zero_child.as_mut().unwrap(),
      Bit::One => self.one_child.as_mut().unwrap(),
    }
  }

  /// Returns the frequency corresponding to the supplied bit.
  fn mut_frequency(&mut self, bit: Bit) -> &mut u64 {
    match bit {
      Bit::Zero => &mut self.zeroes,
      Bit::One => &mut self.ones,
    }
  }

  /// Updates the value of log_weighted_prob. Assumes that log_kt_prob
  /// as well as all values in all children (if any) are up-to-date.
  fn update_weighted_prob(&mut self) {
    if self.is_leaf() {
      self.log_weighted_prob = self.log_kt_prob;
      return;
    }

    let log_weighted_probs =
        self.zero_child.as_ref().unwrap().log_weighted_prob() +
        self.one_child.as_ref().unwrap().log_weighted_prob();
    let exponent = log_weighted_probs - self.log_kt_prob;
    let power = exponent.exp2();

    // The recursive term should be log2(1 + 2^exponent). If the exponent is
    // large enough, 2^exponent is inf. In this case, we approximate
    // log2(1 + 2^exponent) by log2(2^exponent) = exponent.
    let recursive_term =
        if power == f64::INFINITY { exponent } else { (power + 1.0).log2() };

    self.log_weighted_prob = self.log_kt_prob + recursive_term - 1.0;
  }

  /// Returns the number of nodes in the subtree rooted at this node.
  fn size(&self) -> usize {
    1 + match self.zero_child {
      None => 0,
      Some(ref node) => node.size(),
    } + match self.one_child {
      None => 0,
      Some(ref node) => node.size(),
    }
  }

  fn is_leaf(&self) -> bool {
    // By construction we have either both children or none.
    return self.zero_child.is_none();
  }
}
<commit_msg>Fix an inaccurate comment.<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 dinowernli
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use std::f64;

use bitstring::Bit;
use bitstring::Bitstring;

// Open questions:
// - How to declare some fields final
// - How to declare some fields mutable (can be changed for non-mut self)
// - Have the tree implement iter and simplify some methods with "fold".

/// An object capable of predicting observations and rewards based on
/// experience. Predictors have an abstract notion of history which
/// grows over time and represents the experience.
pub trait Predictor {
  /// Returns the size of the currently tracked history.
  fn history_size(&self) -> usize;

  /// Appends the provided bit string to the tracked history.
  fn update(&mut self, bitstring: &Bitstring);

  /// Reverts the context tree to a previous state by undoing update
  /// operations. The specified size must be at most the current size.
  fn revert_to_history_size(&mut self, target_size: usize);

  /// Returns the probability, given the current history, that "bits" are the
  /// next observed symbols.
  fn predict(&mut self, bits: &Bitstring) -> f64;
}

/// Context tree which computes a probability estimate for a sequence of
/// bits based on a mixture model of Markov chains. Lower-degree Markov
/// chains have higher priors in the mixture model, thus formalizing the
/// notion of Occam's Razor.
///
/// In order to get a probability for a sequence, all bits in the sequence
/// must be processed in-order.
pub struct ContextTree {
  root: Node,
  history: Bitstring,
  depth: usize,
}

impl Predictor for ContextTree {
  fn history_size(&self) -> usize {
    self.history.len()
  }

  fn revert_to_history_size(&mut self, target_size: usize) {
    assert!(target_size <= self.history_size());
    while target_size > self.history_size() {
      self.revert_last();
    }
  }

  fn update(&mut self, bitstring: &Bitstring) {
    for bit in bitstring.bits() {
      self.update_bit(*bit);
    }
  }

  fn predict(&mut self, bits: &Bitstring) -> f64 {
    // If we don't have enough history, assume a uniform distribution.
    if !self.has_context() {
      let neg_len = -(bits.len() as i64);
      return (neg_len as f64).exp2();
    }

    // Add all the symbols and store the block probability before and after.
    let initial_size = self.history_size();
    let initial_log_prob = self.log_block_prob();

    self.update(bits);
    let final_log_prob = self.log_block_prob();
    self.revert_to_history_size(initial_size);

    // Let "b" be bits and "h" be our history. We use the equation:
    //      P[hb] = P[h] * P[b | h]
    // <==> log(P[hb]) = log(P[h]) + log(P[b | h])
    // <==> log(P[b | h]) = log(P[hb]) - log(P[h])
    let log_conditional_prob = final_log_prob - initial_log_prob;
    return log_conditional_prob.exp2();
  }
}

impl ContextTree {
  /// The depth of the tree is the distance between leaves and the root.
  /// For a given depth d, the tree will compute a mixture model of all
  /// Markov chains of degree at most d.
  pub fn create(depth: usize) -> Self {
    ContextTree {
      root: Node::create_root(depth, 0),
      history: Bitstring::new(),
      depth: depth,
    }
  }

  /// Returns the total number of nodes in the tree.
  pub fn size(&self) -> usize {
    self.root.size()
  }

  /// Adds a single bit to the history seen by this tree, updating all the
  /// involved nodes if necessary.
  fn update_bit(&mut self, bit: Bit) {
    self.for_node_in_context(&|node: &mut Node| {
      node.update(bit);
    });
    self.history.push(bit);
  }

  /// Removes a single bit from the history seen by this tree, updating all the
  /// involved nodes if necessary.
  fn revert_last(&mut self) {
    let bit = self.history.pop();
    self.for_node_in_context(&|node: &mut Node| {
      node.revert(bit);
    });
  }

  /// Returns log2 of the estimated probability of the current history.
  fn log_block_prob(&mut self) -> f64 {
    return self.root.log_weighted_prob();
  }

  /// Executes the provided closure on the current context, i.e., follows the
  /// current history down to a leaf and executes the closure on every node
  /// from the leaf to the root. Does nothing if the current history is not
  /// long enough to reach a leaf.
  fn for_node_in_context<F: Fn(&mut Node)>(&mut self, closure: &F) {
    if !self.has_context() {
      return;
    }
    self.root.execute(closure, &self.history, 0);
  }

  /// Inidicates whether this tree "has context", i.e., whether or not the
  /// history is long enough to be able to follow a path down to a leaf.
  fn has_context(&self) -> bool { self.history_size() >= self.depth }
}

/// One node in the context tree. Maintains a count of the number
/// of zeroes and ones seen and provides access to partial results
/// of the overall probability estimates computed in the context
/// tree.
struct Node {
  /// Children.
  zero_child: Option<Box<Node>>,
  one_child: Option<Box<Node>>,

  /// Frequencies.
  zeroes: u64,
  ones: u64,

  /// The log2 of the probability of a sequence with self.zeroes zeroes
  /// and self.ones one. Computed using the Krichevsky Trofimov
  /// estimator algorithm.
  log_kt_prob: f64,

  /// The log2 of the weighted block probability of the current sequence.
  /// Funtion of self.zeroes and self.ones and the values recursively
  /// provided by the children of this node (if any), lazily recomputed.
  log_weighted_prob: f64,
}

impl Node {
  /// Creates a node and all its children recursively until the provided
  /// depth is reached.
  pub fn create_root(target_depth: usize, current_depth: usize) -> Self {
    if target_depth == current_depth {
      return Node::new(None, None);  // Leaf.
    } else {
      return Node::new(
          Some(Box::new(Node::create_root(target_depth, current_depth + 1))),
          Some(Box::new(Node::create_root(target_depth, current_depth + 1))));
    }
  }

  fn new(zero_child: Option<Box<Node>>, one_child: Option<Box<Node>>) -> Self {
    // Context trees are complete trees (either both children or no children).
    assert!(zero_child.is_none() == one_child.is_none());

    return Node {
      zero_child: zero_child,
      one_child: one_child,
      zeroes: 0,
      ones: 0,
      log_kt_prob: 0.0,
      log_weighted_prob: 0.0,
    };
  }

  pub fn log_weighted_prob(&self) -> f64 {
    self.log_weighted_prob
  }

  /// Executes the given closure on the appropriate child (if any) and then on
  /// itself.
  pub fn execute<F: Fn(&mut Node)>(
      &mut self,
      closure: &F,
      history: &Bitstring,
      depth: usize) {
    if !self.is_leaf() {
      let bit = history.bit(history.len() - depth - 1);
      self.mut_child(bit).execute(closure, history, depth + 1);
    }
    closure(self);
  }

  /// Updates the state of the node based on the value of the new bit.
  /// Assumes that child nodes (if any) have already been updated.
  pub fn update(&mut self, bit: Bit) {
    *self.mut_frequency(bit) += 1;

    // Old value + 0.5 is the same as new value - 0.5.
    let first_summand = (*self.mut_frequency(bit) as f64 - 0.5).log2();
    let norm_summand = ((self.zeroes + self.ones) as f64).log2();

    self.log_kt_prob = first_summand - norm_summand + self.log_kt_prob;
    self.update_weighted_prob();
  }

  /// Corresponds to undoing one update for the specified bit value.
  /// Assumes that child nodes (if any) have already been reverted.
  pub fn revert(&mut self, bit: Bit) {
    *self.mut_frequency(bit) -= 1;
    // TODO(dinowernli): Update kt probs.
    self.update_weighted_prob();
  }

  /// Returns the child corresponding to the supplied bit. Must not be called
  /// on leaf nodes.
  fn mut_child(&mut self, bit: Bit) -> &mut Node {
    assert!(!self.is_leaf());
    match bit {
      Bit::Zero => self.zero_child.as_mut().unwrap(),
      Bit::One => self.one_child.as_mut().unwrap(),
    }
  }

  /// Returns the frequency corresponding to the supplied bit.
  fn mut_frequency(&mut self, bit: Bit) -> &mut u64 {
    match bit {
      Bit::Zero => &mut self.zeroes,
      Bit::One => &mut self.ones,
    }
  }

  /// Updates the value of log_weighted_prob. Assumes that log_kt_prob
  /// as well as all values in all children (if any) are up-to-date.
  fn update_weighted_prob(&mut self) {
    if self.is_leaf() {
      self.log_weighted_prob = self.log_kt_prob;
      return;
    }

    let log_weighted_probs =
        self.zero_child.as_ref().unwrap().log_weighted_prob() +
        self.one_child.as_ref().unwrap().log_weighted_prob();
    let exponent = log_weighted_probs - self.log_kt_prob;
    let power = exponent.exp2();

    // The recursive term should be log2(1 + 2^exponent). If the exponent is
    // large enough, 2^exponent is inf. In this case, we approximate
    // log2(1 + 2^exponent) by log2(2^exponent) = exponent.
    let recursive_term =
        if power == f64::INFINITY { exponent } else { (power + 1.0).log2() };

    self.log_weighted_prob = self.log_kt_prob + recursive_term - 1.0;
  }

  /// Returns the number of nodes in the subtree rooted at this node.
  fn size(&self) -> usize {
    1 + match self.zero_child {
      None => 0,
      Some(ref node) => node.size(),
    } + match self.one_child {
      None => 0,
      Some(ref node) => node.size(),
    }
  }

  fn is_leaf(&self) -> bool {
    // By construction we have either both children or none.
    return self.zero_child.is_none();
  }
}
<|endoftext|>