<commit_before>/*!
 * Methods for the various MIR types. These are intended for use after
 * building is complete.
 */

use crate::mir::*;
use crate::ty::subst::Subst;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::layout::VariantIdx;
use crate::hir;
use crate::ty::util::IntTypeExt;

#[derive(Copy, Clone, Debug)]
pub struct PlaceTy<'tcx> {
    pub ty: Ty<'tcx>,
    /// Downcast to a particular variant of an enum, if included.
    pub variant_index: Option<VariantIdx>,
}

// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers.
#[cfg(target_arch = "x86_64")]
static_assert_size!(PlaceTy<'_>, 16);

impl<'tcx> PlaceTy<'tcx> {
    pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
        PlaceTy { ty, variant_index: None }
    }

    /// `place_ty.field_ty(tcx, f)` computes the type at a given field
    /// of a record or enum-variant. (Most clients of `PlaceTy` can
    /// instead just extract the relevant type directly from their
    /// `PlaceElem`, but some instances of `ProjectionElem<V, T>` do
    /// not carry a `Ty` for `T`.)
    ///
    /// Note that the resulting type has not been normalized.
    pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: &Field) -> Ty<'tcx> {
        let answer = match self.ty.sty {
            ty::Adt(adt_def, substs) => {
                let variant_def = match self.variant_index {
                    None => adt_def.non_enum_variant(),
                    Some(variant_index) => {
                        assert!(adt_def.is_enum());
                        &adt_def.variants[variant_index]
                    }
                };
                let field_def = &variant_def.fields[f.index()];
                field_def.ty(tcx, substs)
            }
            ty::Tuple(ref tys) => tys[f.index()].expect_ty(),
            _ => bug!("extracting field of non-tuple non-adt: {:?}", self),
        };
        debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer);
        answer
    }

    /// Convenience wrapper around `projection_ty_core` for
    /// `PlaceElem`, where we can just use the `Ty` that is already
    /// stored inline on field projection elems.
    pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: &PlaceElem<'tcx>) -> PlaceTy<'tcx> {
        self.projection_ty_core(tcx, ty::ParamEnv::empty(), elem, |_, _, ty| ty)
    }

    /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
    /// projects `place_ty` onto `elem`, returning the appropriate
    /// `Ty` or downcast variant corresponding to that projection.
    /// The `handle_field` callback must map a `Field` to its `Ty`,
    /// (which should be trivial when `T` = `Ty`).
    pub fn projection_ty_core<V, T>(
        self,
        tcx: TyCtxt<'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        elem: &ProjectionElem<V, T>,
        mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>,
    ) -> PlaceTy<'tcx>
    where
        V: ::std::fmt::Debug,
        T: ::std::fmt::Debug,
    {
        let answer = match *elem {
            ProjectionElem::Deref => {
                let ty = self.ty
                             .builtin_deref(true)
                             .unwrap_or_else(|| {
                                 bug!("deref projection of non-dereferencable ty {:?}", self)
                             })
                             .ty;
                PlaceTy::from_ty(ty)
            }
            ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
                PlaceTy::from_ty(self.ty.builtin_index().unwrap()),
            ProjectionElem::Subslice { from, to } => {
                PlaceTy::from_ty(match self.ty.sty {
                    ty::Array(inner, size) => {
                        let size = size.eval_usize(tcx, param_env);
                        let len = size - (from as u64) - (to as u64);
                        tcx.mk_array(inner, len)
                    }
                    ty::Slice(..) => self.ty,
                    _ => {
                        bug!("cannot subslice non-array type: `{:?}`", self)
                    }
                })
            }
            ProjectionElem::Downcast(_name, index) =>
                PlaceTy { ty: self.ty, variant_index: Some(index) },
            ProjectionElem::Field(ref f, ref fty) =>
                PlaceTy::from_ty(handle_field(&self, f, fty)),
        };
        debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
        answer
    }
}

BraceStructTypeFoldableImpl! {
    impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> {
        ty,
        variant_index,
    }
}

impl<'tcx> Place<'tcx> {
    pub fn ty_from<D>(
        base: &PlaceBase<'tcx>,
        projection: &[PlaceElem<'tcx>],
        local_decls: &D,
        tcx: TyCtxt<'tcx>
    ) -> PlaceTy<'tcx>
        where D: HasLocalDecls<'tcx>
    {
        let mut place_ty = base.ty(local_decls);

        for elem in projection.iter() {
            place_ty = place_ty.projection_ty(tcx, elem);
        }

        place_ty
    }

    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
    where
        D: HasLocalDecls<'tcx>,
    {
        Place::ty_from(&self.base, &self.projection, local_decls, tcx)
    }
}

impl<'tcx> PlaceBase<'tcx> {
    pub fn ty<D>(&self, local_decls: &D) -> PlaceTy<'tcx>
        where D: HasLocalDecls<'tcx>
    {
        match self {
            PlaceBase::Local(index) => PlaceTy::from_ty(local_decls.local_decls()[*index].ty),
            PlaceBase::Static(data) => PlaceTy::from_ty(data.ty),
        }
    }
}

pub enum RvalueInitializationState {
    Shallow,
    Deep
}

impl<'tcx> Rvalue<'tcx> {
    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
    where
        D: HasLocalDecls<'tcx>,
    {
        match *self {
            Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
            Rvalue::Repeat(ref operand, count) => {
                tcx.mk_array(operand.ty(local_decls, tcx), count)
            }
            Rvalue::Ref(reg, bk, ref place) => {
                let place_ty = place.ty(local_decls, tcx).ty;
                tcx.mk_ref(reg,
                    ty::TypeAndMut {
                        ty: place_ty,
                        mutbl: bk.to_mutbl_lossy()
                    }
                )
            }
            Rvalue::Len(..) => tcx.types.usize,
            Rvalue::Cast(.., ty) => ty,
            Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
                let lhs_ty = lhs.ty(local_decls, tcx);
                let rhs_ty = rhs.ty(local_decls, tcx);
                op.ty(tcx, lhs_ty, rhs_ty)
            }
            Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
                let lhs_ty = lhs.ty(local_decls, tcx);
                let rhs_ty = rhs.ty(local_decls, tcx);
                let ty = op.ty(tcx, lhs_ty, rhs_ty);
                tcx.intern_tup(&[ty, tcx.types.bool])
            }
            Rvalue::UnaryOp(UnOp::Not, ref operand) |
            Rvalue::UnaryOp(UnOp::Neg, ref operand) => {
                operand.ty(local_decls, tcx)
            }
            Rvalue::Discriminant(ref place) => {
                let ty = place.ty(local_decls, tcx).ty;
                match ty.sty {
                    ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx),
                    ty::Generator(_, substs, _) => substs.discr_ty(tcx),
                    _ => {
                        // This can only be `0`, for now, so `u8` will suffice.
                        tcx.types.u8
                    }
                }
            }
            Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
            Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize,
            Rvalue::Aggregate(ref ak, ref ops) => {
                match **ak {
                    AggregateKind::Array(ty) => {
                        tcx.mk_array(ty, ops.len() as u64)
                    }
                    AggregateKind::Tuple => {
                        tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx)))
                    }
                    AggregateKind::Adt(def, _, substs, _, _) => {
                        tcx.type_of(def.did).subst(tcx, substs)
                    }
                    AggregateKind::Closure(did, substs) => {
                        tcx.mk_closure(did, substs)
                    }
                    AggregateKind::Generator(did, substs, movability) => {
                        tcx.mk_generator(did, substs, movability)
                    }
                }
            }
        }
    }

    #[inline]
    /// Returns `true` if this rvalue is deeply initialized (most rvalues) or
    /// whether its only shallowly initialized (`Rvalue::Box`).
    pub fn initialization_state(&self) -> RvalueInitializationState {
        match *self {
            Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow,
            _ => RvalueInitializationState::Deep
        }
    }
}

impl<'tcx> Operand<'tcx> {
    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
    where
        D: HasLocalDecls<'tcx>,
    {
        match self {
            &Operand::Copy(ref l) |
            &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
            &Operand::Constant(ref c) => c.literal.ty,
        }
    }
}

impl<'tcx> BinOp {
    pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> {
        // FIXME: handle SIMD correctly
        match self {
            &BinOp::Add | &BinOp::Sub | &BinOp::Mul | &BinOp::Div | &BinOp::Rem |
            &BinOp::BitXor | &BinOp::BitAnd | &BinOp::BitOr => {
                // these should be integers or floats of the same size.
                assert_eq!(lhs_ty, rhs_ty);
                lhs_ty
            }
            &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => {
                lhs_ty // lhs_ty can be != rhs_ty
            }
            &BinOp::Eq | &BinOp::Lt | &BinOp::Le |
            &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
                tcx.types.bool
            }
        }
    }
}

impl BorrowKind {
    pub fn to_mutbl_lossy(self) -> hir::Mutability {
        match self {
            BorrowKind::Mut { .. } => hir::MutMutable,
            BorrowKind::Shared => hir::MutImmutable,

            // We have no type corresponding to a unique imm borrow, so
            // use `&mut`. It gives all the capabilities of an `&uniq`
            // and hence is a safe "over approximation".
            BorrowKind::Unique => hir::MutMutable,

            // We have no type corresponding to a shallow borrow, so use
            // `&` as an approximation.
            BorrowKind::Shallow => hir::MutImmutable,
        }
    }
}

impl BinOp {
    pub fn to_hir_binop(self) -> hir::BinOpKind {
        match self {
            BinOp::Add => hir::BinOpKind::Add,
            BinOp::Sub => hir::BinOpKind::Sub,
            BinOp::Mul => hir::BinOpKind::Mul,
            BinOp::Div => hir::BinOpKind::Div,
            BinOp::Rem => hir::BinOpKind::Rem,
            BinOp::BitXor => hir::BinOpKind::BitXor,
            BinOp::BitAnd => hir::BinOpKind::BitAnd,
            BinOp::BitOr => hir::BinOpKind::BitOr,
            BinOp::Shl => hir::BinOpKind::Shl,
            BinOp::Shr => hir::BinOpKind::Shr,
            BinOp::Eq => hir::BinOpKind::Eq,
            BinOp::Ne => hir::BinOpKind::Ne,
            BinOp::Lt => hir::BinOpKind::Lt,
            BinOp::Gt => hir::BinOpKind::Gt,
            BinOp::Le => hir::BinOpKind::Le,
            BinOp::Ge => hir::BinOpKind::Ge,
            BinOp::Offset => unreachable!()
        }
    }
}
<commit_msg>Use fold<commit_after>/*!
 * Methods for the various MIR types. These are intended for use after
 * building is complete.
 */

use crate::mir::*;
use crate::ty::subst::Subst;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::layout::VariantIdx;
use crate::hir;
use crate::ty::util::IntTypeExt;

#[derive(Copy, Clone, Debug)]
pub struct PlaceTy<'tcx> {
    pub ty: Ty<'tcx>,
    /// Downcast to a particular variant of an enum, if included.
    pub variant_index: Option<VariantIdx>,
}

// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers.
#[cfg(target_arch = "x86_64")]
static_assert_size!(PlaceTy<'_>, 16);

impl<'tcx> PlaceTy<'tcx> {
    pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
        PlaceTy { ty, variant_index: None }
    }

    /// `place_ty.field_ty(tcx, f)` computes the type at a given field
    /// of a record or enum-variant. (Most clients of `PlaceTy` can
    /// instead just extract the relevant type directly from their
    /// `PlaceElem`, but some instances of `ProjectionElem<V, T>` do
    /// not carry a `Ty` for `T`.)
    ///
    /// Note that the resulting type has not been normalized.
    pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: &Field) -> Ty<'tcx> {
        let answer = match self.ty.sty {
            ty::Adt(adt_def, substs) => {
                let variant_def = match self.variant_index {
                    None => adt_def.non_enum_variant(),
                    Some(variant_index) => {
                        assert!(adt_def.is_enum());
                        &adt_def.variants[variant_index]
                    }
                };
                let field_def = &variant_def.fields[f.index()];
                field_def.ty(tcx, substs)
            }
            ty::Tuple(ref tys) => tys[f.index()].expect_ty(),
            _ => bug!("extracting field of non-tuple non-adt: {:?}", self),
        };
        debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer);
        answer
    }

    /// Convenience wrapper around `projection_ty_core` for
    /// `PlaceElem`, where we can just use the `Ty` that is already
    /// stored inline on field projection elems.
    pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: &PlaceElem<'tcx>) -> PlaceTy<'tcx> {
        self.projection_ty_core(tcx, ty::ParamEnv::empty(), elem, |_, _, ty| ty)
    }

    /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
    /// projects `place_ty` onto `elem`, returning the appropriate
    /// `Ty` or downcast variant corresponding to that projection.
    /// The `handle_field` callback must map a `Field` to its `Ty`,
    /// (which should be trivial when `T` = `Ty`).
    pub fn projection_ty_core<V, T>(
        self,
        tcx: TyCtxt<'tcx>,
        param_env: ty::ParamEnv<'tcx>,
        elem: &ProjectionElem<V, T>,
        mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>,
    ) -> PlaceTy<'tcx>
    where
        V: ::std::fmt::Debug,
        T: ::std::fmt::Debug,
    {
        let answer = match *elem {
            ProjectionElem::Deref => {
                let ty = self.ty
                             .builtin_deref(true)
                             .unwrap_or_else(|| {
                                 bug!("deref projection of non-dereferencable ty {:?}", self)
                             })
                             .ty;
                PlaceTy::from_ty(ty)
            }
            ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
                PlaceTy::from_ty(self.ty.builtin_index().unwrap()),
            ProjectionElem::Subslice { from, to } => {
                PlaceTy::from_ty(match self.ty.sty {
                    ty::Array(inner, size) => {
                        let size = size.eval_usize(tcx, param_env);
                        let len = size - (from as u64) - (to as u64);
                        tcx.mk_array(inner, len)
                    }
                    ty::Slice(..) => self.ty,
                    _ => {
                        bug!("cannot subslice non-array type: `{:?}`", self)
                    }
                })
            }
            ProjectionElem::Downcast(_name, index) =>
                PlaceTy { ty: self.ty, variant_index: Some(index) },
            ProjectionElem::Field(ref f, ref fty) =>
                PlaceTy::from_ty(handle_field(&self, f, fty)),
        };
        debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
        answer
    }
}

BraceStructTypeFoldableImpl! {
    impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> {
        ty,
        variant_index,
    }
}

impl<'tcx> Place<'tcx> {
    pub fn ty_from<D>(
        base: &PlaceBase<'tcx>,
        projection: &[PlaceElem<'tcx>],
        local_decls: &D,
        tcx: TyCtxt<'tcx>
    ) -> PlaceTy<'tcx>
        where D: HasLocalDecls<'tcx>
    {
        projection.iter().fold(
            base.ty(local_decls),
            |place_ty, elem| place_ty.projection_ty(tcx, elem)
        )
    }

    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
    where
        D: HasLocalDecls<'tcx>,
    {
        Place::ty_from(&self.base, &self.projection, local_decls, tcx)
    }
}

impl<'tcx> PlaceBase<'tcx> {
    pub fn ty<D>(&self, local_decls: &D) -> PlaceTy<'tcx>
        where D: HasLocalDecls<'tcx>
    {
        match self {
            PlaceBase::Local(index) => PlaceTy::from_ty(local_decls.local_decls()[*index].ty),
            PlaceBase::Static(data) => PlaceTy::from_ty(data.ty),
        }
    }
}

pub enum RvalueInitializationState {
    Shallow,
    Deep
}

impl<'tcx> Rvalue<'tcx> {
    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
    where
        D: HasLocalDecls<'tcx>,
    {
        match *self {
            Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
            Rvalue::Repeat(ref operand, count) => {
                tcx.mk_array(operand.ty(local_decls, tcx), count)
            }
            Rvalue::Ref(reg, bk, ref place) => {
                let place_ty = place.ty(local_decls, tcx).ty;
                tcx.mk_ref(reg,
                    ty::TypeAndMut {
                        ty: place_ty,
                        mutbl: bk.to_mutbl_lossy()
                    }
                )
            }
            Rvalue::Len(..) => tcx.types.usize,
            Rvalue::Cast(.., ty) => ty,
            Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
                let lhs_ty = lhs.ty(local_decls, tcx);
                let rhs_ty = rhs.ty(local_decls, tcx);
                op.ty(tcx, lhs_ty, rhs_ty)
            }
            Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
                let lhs_ty = lhs.ty(local_decls, tcx);
                let rhs_ty = rhs.ty(local_decls, tcx);
                let ty = op.ty(tcx, lhs_ty, rhs_ty);
                tcx.intern_tup(&[ty, tcx.types.bool])
            }
            Rvalue::UnaryOp(UnOp::Not, ref operand) |
            Rvalue::UnaryOp(UnOp::Neg, ref operand) => {
                operand.ty(local_decls, tcx)
            }
            Rvalue::Discriminant(ref place) => {
                let ty = place.ty(local_decls, tcx).ty;
                match ty.sty {
                    ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx),
                    ty::Generator(_, substs, _) => substs.discr_ty(tcx),
                    _ => {
                        // This can only be `0`, for now, so `u8` will suffice.
                        tcx.types.u8
                    }
                }
            }
            Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
            Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize,
            Rvalue::Aggregate(ref ak, ref ops) => {
                match **ak {
                    AggregateKind::Array(ty) => {
                        tcx.mk_array(ty, ops.len() as u64)
                    }
                    AggregateKind::Tuple => {
                        tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx)))
                    }
                    AggregateKind::Adt(def, _, substs, _, _) => {
                        tcx.type_of(def.did).subst(tcx, substs)
                    }
                    AggregateKind::Closure(did, substs) => {
                        tcx.mk_closure(did, substs)
                    }
                    AggregateKind::Generator(did, substs, movability) => {
                        tcx.mk_generator(did, substs, movability)
                    }
                }
            }
        }
    }

    #[inline]
    /// Returns `true` if this rvalue is deeply initialized (most rvalues) or
    /// whether its only shallowly initialized (`Rvalue::Box`).
    pub fn initialization_state(&self) -> RvalueInitializationState {
        match *self {
            Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow,
            _ => RvalueInitializationState::Deep
        }
    }
}

impl<'tcx> Operand<'tcx> {
    pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
    where
        D: HasLocalDecls<'tcx>,
    {
        match self {
            &Operand::Copy(ref l) |
            &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
            &Operand::Constant(ref c) => c.literal.ty,
        }
    }
}

impl<'tcx> BinOp {
    pub fn ty(&self, tcx: TyCtxt<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>) -> Ty<'tcx> {
        // FIXME: handle SIMD correctly
        match self {
            &BinOp::Add | &BinOp::Sub | &BinOp::Mul | &BinOp::Div | &BinOp::Rem |
            &BinOp::BitXor | &BinOp::BitAnd | &BinOp::BitOr => {
                // these should be integers or floats of the same size.
                assert_eq!(lhs_ty, rhs_ty);
                lhs_ty
            }
            &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => {
                lhs_ty // lhs_ty can be != rhs_ty
            }
            &BinOp::Eq | &BinOp::Lt | &BinOp::Le |
            &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
                tcx.types.bool
            }
        }
    }
}

impl BorrowKind {
    pub fn to_mutbl_lossy(self) -> hir::Mutability {
        match self {
            BorrowKind::Mut { .. } => hir::MutMutable,
            BorrowKind::Shared => hir::MutImmutable,

            // We have no type corresponding to a unique imm borrow, so
            // use `&mut`. It gives all the capabilities of an `&uniq`
            // and hence is a safe "over approximation".
            BorrowKind::Unique => hir::MutMutable,

            // We have no type corresponding to a shallow borrow, so use
            // `&` as an approximation.
            BorrowKind::Shallow => hir::MutImmutable,
        }
    }
}

impl BinOp {
    pub fn to_hir_binop(self) -> hir::BinOpKind {
        match self {
            BinOp::Add => hir::BinOpKind::Add,
            BinOp::Sub => hir::BinOpKind::Sub,
            BinOp::Mul => hir::BinOpKind::Mul,
            BinOp::Div => hir::BinOpKind::Div,
            BinOp::Rem => hir::BinOpKind::Rem,
            BinOp::BitXor => hir::BinOpKind::BitXor,
            BinOp::BitAnd => hir::BinOpKind::BitAnd,
            BinOp::BitOr => hir::BinOpKind::BitOr,
            BinOp::Shl => hir::BinOpKind::Shl,
            BinOp::Shr => hir::BinOpKind::Shr,
            BinOp::Eq => hir::BinOpKind::Eq,
            BinOp::Ne => hir::BinOpKind::Ne,
            BinOp::Lt => hir::BinOpKind::Lt,
            BinOp::Gt => hir::BinOpKind::Gt,
            BinOp::Le => hir::BinOpKind::Le,
            BinOp::Ge => hir::BinOpKind::Ge,
            BinOp::Offset => unreachable!()
        }
    }
}
<|endoftext|>


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

//! Checks for uses of mutex where an atomic value could be used
//!
//! This lint is **warn** by default

use crate::rustc::hir::Expr;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::{self, Ty};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast;
use crate::utils::{match_type, paths, span_lint};

/// **What it does:** Checks for usages of `Mutex<X>` where an atomic will do.
///
/// **Why is this bad?** Using a mutex just to make access to a plain bool or
/// reference sequential is shooting flies with cannons.
/// `std::atomic::AtomicBool` and `std::atomic::AtomicPtr` are leaner and
/// faster.
///
/// **Known problems:** This lint cannot detect if the mutex is actually used
/// for waiting before a critical section.
///
/// **Example:**
/// ```rust
/// let x = Mutex::new(&y);
/// ```
declare_clippy_lint! {
    pub MUTEX_ATOMIC,
    perf,
    "using a mutex where an atomic value could be used instead"
}

/// **What it does:** Checks for usages of `Mutex<X>` where `X` is an integral
/// type.
///
/// **Why is this bad?** Using a mutex just to make access to a plain integer
/// sequential is
/// shooting flies with cannons. `std::atomic::usize` is leaner and faster.
///
/// **Known problems:** This lint cannot detect if the mutex is actually used
/// for waiting before a critical section.
///
/// **Example:**
/// ```rust
/// let x = Mutex::new(0usize);
/// ```
declare_clippy_lint! {
    pub MUTEX_INTEGER,
    nursery,
    "using a mutex for an integer type"
}

impl LintPass for MutexAtomic {
    fn get_lints(&self) -> LintArray {
        lint_array!(MUTEX_ATOMIC, MUTEX_INTEGER)
    }
}

pub struct MutexAtomic;

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutexAtomic {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        let ty = cx.tables.expr_ty(expr);
        if let ty::Adt(_, subst) = ty.sty {
            if match_type(cx, ty, &paths::MUTEX) {
                let mutex_param = subst.type_at(0);
                if let Some(atomic_name) = get_atomic_name(mutex_param) {
                    let msg = format!(
                        "Consider using an {} instead of a Mutex here. If you just want the locking \
                         behaviour and not the internal type, consider using Mutex<()>.",
                        atomic_name
                    );
                    match mutex_param.sty {
                        ty::Uint(t) if t != ast::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
                        ty::Int(t) if t != ast::IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
                        _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg),
                    };
                }
            }
        }
    }
}

fn get_atomic_name(ty: Ty<'_>) -> Option<(&'static str)> {
    match ty.sty {
        ty::Bool => Some("AtomicBool"),
        ty::Uint(_) => Some("AtomicUsize"),
        ty::Int(_) => Some("AtomicIsize"),
        ty::RawPtr(_) => Some("AtomicPtr"),
        _ => None,
    }
}
<commit_msg>Auto merge of #3566 - kinnison:kinnison/typofix, r=phansch<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Checks for uses of mutex where an atomic value could be used
//!
//! This lint is **warn** by default

use crate::rustc::hir::Expr;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::{self, Ty};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast;
use crate::utils::{match_type, paths, span_lint};

/// **What it does:** Checks for usages of `Mutex<X>` where an atomic will do.
///
/// **Why is this bad?** Using a mutex just to make access to a plain bool or
/// reference sequential is shooting flies with cannons.
/// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and
/// faster.
///
/// **Known problems:** This lint cannot detect if the mutex is actually used
/// for waiting before a critical section.
///
/// **Example:**
/// ```rust
/// let x = Mutex::new(&y);
/// ```
declare_clippy_lint! {
    pub MUTEX_ATOMIC,
    perf,
    "using a mutex where an atomic value could be used instead"
}

/// **What it does:** Checks for usages of `Mutex<X>` where `X` is an integral
/// type.
///
/// **Why is this bad?** Using a mutex just to make access to a plain integer
/// sequential is
/// shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster.
///
/// **Known problems:** This lint cannot detect if the mutex is actually used
/// for waiting before a critical section.
///
/// **Example:**
/// ```rust
/// let x = Mutex::new(0usize);
/// ```
declare_clippy_lint! {
    pub MUTEX_INTEGER,
    nursery,
    "using a mutex for an integer type"
}

impl LintPass for MutexAtomic {
    fn get_lints(&self) -> LintArray {
        lint_array!(MUTEX_ATOMIC, MUTEX_INTEGER)
    }
}

pub struct MutexAtomic;

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutexAtomic {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        let ty = cx.tables.expr_ty(expr);
        if let ty::Adt(_, subst) = ty.sty {
            if match_type(cx, ty, &paths::MUTEX) {
                let mutex_param = subst.type_at(0);
                if let Some(atomic_name) = get_atomic_name(mutex_param) {
                    let msg = format!(
                        "Consider using an {} instead of a Mutex here. If you just want the locking \
                         behaviour and not the internal type, consider using Mutex<()>.",
                        atomic_name
                    );
                    match mutex_param.sty {
                        ty::Uint(t) if t != ast::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
                        ty::Int(t) if t != ast::IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
                        _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg),
                    };
                }
            }
        }
    }
}

fn get_atomic_name(ty: Ty<'_>) -> Option<(&'static str)> {
    match ty.sty {
        ty::Bool => Some("AtomicBool"),
        ty::Uint(_) => Some("AtomicUsize"),
        ty::Int(_) => Some("AtomicIsize"),
        ty::RawPtr(_) => Some("AtomicPtr"),
        _ => None,
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Native representation of JS Promise values.
//!
//! This implementation differs from the traditional Rust DOM object, because the reflector
//! is provided by SpiderMonkey and has no knowledge of an associated native representation
//! (ie. dom::Promise). This means that native instances use native reference counting (Rc)
//! to ensure that no memory is leaked, which means that there can be multiple instances of
//! native Promise values that refer to the same JS value yet are distinct native objects
//! (ie. address equality for the native objects is meaningless).

use dom::bindings::conversions::root_from_object;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::reflector::{DomObject, MutDomObject, Reflector};
use dom::bindings::utils::AsCCharPtrPtr;
use dom::globalscope::GlobalScope;
use dom::promisenativehandler::PromiseNativeHandler;
use dom_struct::dom_struct;
use js::conversions::ToJSValConvertible;
use js::jsapi::{CallOriginalPromiseResolve, CallOriginalPromiseReject};
use js::jsapi::{JSAutoCompartment, CallArgs, JS_GetFunctionObject, JS_NewFunction};
use js::jsapi::{JSContext, HandleValue, HandleObject, IsPromiseObject, GetFunctionNativeReserved};
use js::jsapi::{JS_ClearPendingException, JSObject, AddRawValueRoot, RemoveRawValueRoot, PromiseState};
use js::jsapi::{MutableHandleObject, NewPromiseObject, ResolvePromise, RejectPromise, GetPromiseState};
use js::jsapi::{SetFunctionNativeReserved, NewFunctionWithReserved, AddPromiseReactions};
use js::jsapi::Heap;
use js::jsval::{JSVal, UndefinedValue, ObjectValue, Int32Value};
use std::ptr;
use std::rc::Rc;

#[dom_struct]
pub struct Promise {
    reflector: Reflector,
    /// Since Promise values are natively reference counted without the knowledge of
    /// the SpiderMonkey GC, an explicit root for the reflector is stored while any
    /// native instance exists. This ensures that the reflector will never be GCed
    /// while native code could still interact with its native representation.
    #[ignore_malloc_size_of = "SM handles JS values"]
    permanent_js_root: Heap<JSVal>,
}

/// Private helper to enable adding new methods to Rc<Promise>.
trait PromiseHelper {
    #[allow(unsafe_code)]
    unsafe fn initialize(&self, cx: *mut JSContext);
}

impl PromiseHelper for Rc<Promise> {
    #[allow(unsafe_code)]
    unsafe fn initialize(&self, cx: *mut JSContext) {
        let obj = self.reflector().get_jsobject();
        self.permanent_js_root.set(ObjectValue(*obj));
        assert!(AddRawValueRoot(cx,
                                self.permanent_js_root.get_unsafe(),
                                b"Promise::root\0".as_c_char_ptr()));
    }
}

impl Drop for Promise {
    #[allow(unsafe_code)]
    fn drop(&mut self) {
        let cx = self.global().get_cx();
        unsafe {
            RemoveRawValueRoot(cx, self.permanent_js_root.get_unsafe());
        }
    }
}

impl Promise {
    #[allow(unsafe_code)]
    pub fn new(global: &GlobalScope) -> Rc<Promise> {
        let cx = global.get_cx();
        rooted!(in(cx) let mut obj = ptr::null_mut::<JSObject>());
        unsafe {
            Promise::create_js_promise(cx, HandleObject::null(), obj.handle_mut());
            Promise::new_with_js_promise(obj.handle(), cx)
        }
    }

    #[allow(unsafe_code, unrooted_must_root)]
    pub fn duplicate(&self) -> Rc<Promise> {
        let cx = self.global().get_cx();
        unsafe {
            Promise::new_with_js_promise(self.reflector().get_jsobject(), cx)
        }
    }

    #[allow(unsafe_code, unrooted_must_root)]
    unsafe fn new_with_js_promise(obj: HandleObject, cx: *mut JSContext) -> Rc<Promise> {
        assert!(IsPromiseObject(obj));
        let promise = Promise {
            reflector: Reflector::new(),
            permanent_js_root: Heap::default(),
        };
        let mut promise = Rc::new(promise);
        Rc::get_mut(&mut promise).unwrap().init_reflector(obj.get());
        promise.initialize(cx);
        promise
    }

    #[allow(unsafe_code)]
    unsafe fn create_js_promise(cx: *mut JSContext, proto: HandleObject, obj: MutableHandleObject) {
        let do_nothing_func = JS_NewFunction(cx, Some(do_nothing_promise_executor), /* nargs = */ 2,
                                             /* flags = */ 0, ptr::null());
        assert!(!do_nothing_func.is_null());
        rooted!(in(cx) let do_nothing_obj = JS_GetFunctionObject(do_nothing_func));
        assert!(!do_nothing_obj.is_null());
        obj.set(NewPromiseObject(cx, do_nothing_obj.handle(), proto));
        assert!(!obj.is_null());
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn new_resolved(
        global: &GlobalScope,
        cx: *mut JSContext,
        value: HandleValue,
    ) -> Fallible<Rc<Promise>> {
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        rooted!(in(cx) let p = CallOriginalPromiseResolve(cx, value));
        assert!(!p.handle().is_null());
        Ok(Promise::new_with_js_promise(p.handle(), cx))
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn new_rejected(
        global: &GlobalScope,
        cx: *mut JSContext,
        value: HandleValue,
    ) -> Fallible<Rc<Promise>> {
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        rooted!(in(cx) let p = CallOriginalPromiseReject(cx, value));
        assert!(!p.handle().is_null());
        Ok(Promise::new_with_js_promise(p.handle(), cx))
    }

    #[allow(unsafe_code)]
    pub fn resolve_native<T>(&self, val: &T) where T: ToJSValConvertible {
        let cx = self.global().get_cx();
        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
        rooted!(in(cx) let mut v = UndefinedValue());
        unsafe {
            val.to_jsval(cx, v.handle_mut());
            self.resolve(cx, v.handle());
        }
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn resolve(&self, cx: *mut JSContext, value: HandleValue) {
        if !ResolvePromise(cx, self.promise_obj(), value) {
            JS_ClearPendingException(cx);
        }
    }

    #[allow(unsafe_code)]
    pub fn reject_native<T>(&self, val: &T) where T: ToJSValConvertible {
        let cx = self.global().get_cx();
        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
        rooted!(in(cx) let mut v = UndefinedValue());
        unsafe {
            val.to_jsval(cx, v.handle_mut());
            self.reject(cx, v.handle());
        }
    }

    #[allow(unsafe_code)]
    pub fn reject_error(&self, error: Error) {
        let cx = self.global().get_cx();
        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
        rooted!(in(cx) let mut v = UndefinedValue());
        unsafe {
            error.to_jsval(cx, &self.global(), v.handle_mut());
            self.reject(cx, v.handle());
        }
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn reject(&self, cx: *mut JSContext, value: HandleValue) {
        if !RejectPromise(cx, self.promise_obj(), value) {
            JS_ClearPendingException(cx);
        }
    }

    #[allow(unsafe_code)]
    pub fn is_fulfilled(&self) -> bool {
        let state = unsafe { GetPromiseState(self.promise_obj()) };
        match state {
            PromiseState::Rejected | PromiseState::Fulfilled => true,
            _ => false
        }
    }

    #[allow(unsafe_code)]
    fn promise_obj(&self) -> HandleObject {
        let obj = self.reflector().get_jsobject();
        unsafe {
            assert!(IsPromiseObject(obj));
        }
        obj
    }

    #[allow(unsafe_code)]
    pub fn append_native_handler(&self, handler: &PromiseNativeHandler) {
        let cx = self.global().get_cx();
        rooted!(in(cx) let resolve_func =
                create_native_handler_function(cx,
                                               handler.reflector().get_jsobject(),
                                               NativeHandlerTask::Resolve));

        rooted!(in(cx) let reject_func =
                create_native_handler_function(cx,
                                               handler.reflector().get_jsobject(),
                                               NativeHandlerTask::Reject));

        unsafe {
            let ok = AddPromiseReactions(cx,
                                         self.promise_obj(),
                                         resolve_func.handle(),
                                         reject_func.handle());
            assert!(ok);
        }
    }
}

#[allow(unsafe_code)]
unsafe extern fn do_nothing_promise_executor(_cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
    let args = CallArgs::from_vp(vp, argc);
    *args.rval() = UndefinedValue();
    true
}

const SLOT_NATIVEHANDLER: usize = 0;
const SLOT_NATIVEHANDLER_TASK: usize = 1;

#[derive(PartialEq)]
enum NativeHandlerTask {
    Resolve = 0,
    Reject = 1,
}

#[allow(unsafe_code)]
unsafe extern fn native_handler_callback(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
    let args = CallArgs::from_vp(vp, argc);
    rooted!(in(cx) let v = *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER));
    assert!(v.get().is_object());

    let handler = root_from_object::<PromiseNativeHandler>(v.to_object())
        .expect("unexpected value for native handler in promise native handler callback");

    rooted!(in(cx) let v = *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER_TASK));
    match v.to_int32() {
        v if v == NativeHandlerTask::Resolve as i32 => handler.resolved_callback(cx, args.get(0)),
        v if v == NativeHandlerTask::Reject as i32 => handler.rejected_callback(cx, args.get(0)),
        _ => panic!("unexpected native handler task value"),
    };

    true
}

#[allow(unsafe_code)]
fn create_native_handler_function(cx: *mut JSContext,
                                  holder: HandleObject,
                                  task: NativeHandlerTask) -> *mut JSObject {
    unsafe {
        let func = NewFunctionWithReserved(cx, Some(native_handler_callback), 1, 0, ptr::null());
        assert!(!func.is_null());

        rooted!(in(cx) let obj = JS_GetFunctionObject(func));
        assert!(!obj.is_null());
        SetFunctionNativeReserved(obj.get(),
                                  SLOT_NATIVEHANDLER,
                                  &ObjectValue(*holder));
        SetFunctionNativeReserved(obj.get(),
                                  SLOT_NATIVEHANDLER_TASK,
                                  &Int32Value(task as i32));
        obj.get()
    }
}

<commit_msg>Don't access the reflector when dropping a Promise (fixes #18651)<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Native representation of JS Promise values.
//!
//! This implementation differs from the traditional Rust DOM object, because the reflector
//! is provided by SpiderMonkey and has no knowledge of an associated native representation
//! (ie. dom::Promise). This means that native instances use native reference counting (Rc)
//! to ensure that no memory is leaked, which means that there can be multiple instances of
//! native Promise values that refer to the same JS value yet are distinct native objects
//! (ie. address equality for the native objects is meaningless).

use dom::bindings::conversions::root_from_object;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::reflector::{DomObject, MutDomObject, Reflector};
use dom::bindings::utils::AsCCharPtrPtr;
use dom::globalscope::GlobalScope;
use dom::promisenativehandler::PromiseNativeHandler;
use dom_struct::dom_struct;
use js::conversions::ToJSValConvertible;
use js::jsapi::{AddPromiseReactions, AddRawValueRoot, CallArgs, CallOriginalPromiseReject};
use js::jsapi::{CallOriginalPromiseResolve, GetFunctionNativeReserved, GetPromiseState};
use js::jsapi::{HandleObject, HandleValue, Heap, IsPromiseObject, JS_ClearPendingException};
use js::jsapi::{JSAutoCompartment, JSContext, JSObject, JS_GetContext, JS_GetFunctionObject};
use js::jsapi::{JS_GetObjectRuntime, JS_NewFunction, MutableHandleObject};
use js::jsapi::{NewFunctionWithReserved, NewPromiseObject, PromiseState, RejectPromise};
use js::jsapi::{RemoveRawValueRoot, ResolvePromise, SetFunctionNativeReserved};
use js::jsval::{JSVal, UndefinedValue, ObjectValue, Int32Value};
use std::ptr;
use std::rc::Rc;

#[dom_struct]
pub struct Promise {
    reflector: Reflector,
    /// Since Promise values are natively reference counted without the knowledge of
    /// the SpiderMonkey GC, an explicit root for the reflector is stored while any
    /// native instance exists. This ensures that the reflector will never be GCed
    /// while native code could still interact with its native representation.
    #[ignore_malloc_size_of = "SM handles JS values"]
    permanent_js_root: Heap<JSVal>,
}

/// Private helper to enable adding new methods to Rc<Promise>.
trait PromiseHelper {
    #[allow(unsafe_code)]
    unsafe fn initialize(&self, cx: *mut JSContext);
}

impl PromiseHelper for Rc<Promise> {
    #[allow(unsafe_code)]
    unsafe fn initialize(&self, cx: *mut JSContext) {
        let obj = self.reflector().get_jsobject();
        self.permanent_js_root.set(ObjectValue(*obj));
        assert!(AddRawValueRoot(cx,
                                self.permanent_js_root.get_unsafe(),
                                b"Promise::root\0".as_c_char_ptr()));
    }
}

impl Drop for Promise {
    #[allow(unsafe_code)]
    fn drop(&mut self) {
        unsafe {
            let object = self.permanent_js_root.get().to_object();
            assert!(!object.is_null());
            let runtime = JS_GetObjectRuntime(object);
            assert!(!runtime.is_null());
            let cx = JS_GetContext(runtime);
            assert!(!cx.is_null());
            RemoveRawValueRoot(cx, self.permanent_js_root.get_unsafe());
        }
    }
}

impl Promise {
    #[allow(unsafe_code)]
    pub fn new(global: &GlobalScope) -> Rc<Promise> {
        let cx = global.get_cx();
        rooted!(in(cx) let mut obj = ptr::null_mut::<JSObject>());
        unsafe {
            Promise::create_js_promise(cx, HandleObject::null(), obj.handle_mut());
            Promise::new_with_js_promise(obj.handle(), cx)
        }
    }

    #[allow(unsafe_code, unrooted_must_root)]
    pub fn duplicate(&self) -> Rc<Promise> {
        let cx = self.global().get_cx();
        unsafe {
            Promise::new_with_js_promise(self.reflector().get_jsobject(), cx)
        }
    }

    #[allow(unsafe_code, unrooted_must_root)]
    unsafe fn new_with_js_promise(obj: HandleObject, cx: *mut JSContext) -> Rc<Promise> {
        assert!(IsPromiseObject(obj));
        let promise = Promise {
            reflector: Reflector::new(),
            permanent_js_root: Heap::default(),
        };
        let mut promise = Rc::new(promise);
        Rc::get_mut(&mut promise).unwrap().init_reflector(obj.get());
        promise.initialize(cx);
        promise
    }

    #[allow(unsafe_code)]
    unsafe fn create_js_promise(cx: *mut JSContext, proto: HandleObject, obj: MutableHandleObject) {
        let do_nothing_func = JS_NewFunction(cx, Some(do_nothing_promise_executor), /* nargs = */ 2,
                                             /* flags = */ 0, ptr::null());
        assert!(!do_nothing_func.is_null());
        rooted!(in(cx) let do_nothing_obj = JS_GetFunctionObject(do_nothing_func));
        assert!(!do_nothing_obj.is_null());
        obj.set(NewPromiseObject(cx, do_nothing_obj.handle(), proto));
        assert!(!obj.is_null());
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn new_resolved(
        global: &GlobalScope,
        cx: *mut JSContext,
        value: HandleValue,
    ) -> Fallible<Rc<Promise>> {
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        rooted!(in(cx) let p = CallOriginalPromiseResolve(cx, value));
        assert!(!p.handle().is_null());
        Ok(Promise::new_with_js_promise(p.handle(), cx))
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn new_rejected(
        global: &GlobalScope,
        cx: *mut JSContext,
        value: HandleValue,
    ) -> Fallible<Rc<Promise>> {
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        rooted!(in(cx) let p = CallOriginalPromiseReject(cx, value));
        assert!(!p.handle().is_null());
        Ok(Promise::new_with_js_promise(p.handle(), cx))
    }

    #[allow(unsafe_code)]
    pub fn resolve_native<T>(&self, val: &T) where T: ToJSValConvertible {
        let cx = self.global().get_cx();
        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
        rooted!(in(cx) let mut v = UndefinedValue());
        unsafe {
            val.to_jsval(cx, v.handle_mut());
            self.resolve(cx, v.handle());
        }
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn resolve(&self, cx: *mut JSContext, value: HandleValue) {
        if !ResolvePromise(cx, self.promise_obj(), value) {
            JS_ClearPendingException(cx);
        }
    }

    #[allow(unsafe_code)]
    pub fn reject_native<T>(&self, val: &T) where T: ToJSValConvertible {
        let cx = self.global().get_cx();
        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
        rooted!(in(cx) let mut v = UndefinedValue());
        unsafe {
            val.to_jsval(cx, v.handle_mut());
            self.reject(cx, v.handle());
        }
    }

    #[allow(unsafe_code)]
    pub fn reject_error(&self, error: Error) {
        let cx = self.global().get_cx();
        let _ac = JSAutoCompartment::new(cx, self.reflector().get_jsobject().get());
        rooted!(in(cx) let mut v = UndefinedValue());
        unsafe {
            error.to_jsval(cx, &self.global(), v.handle_mut());
            self.reject(cx, v.handle());
        }
    }

    #[allow(unrooted_must_root, unsafe_code)]
    pub unsafe fn reject(&self, cx: *mut JSContext, value: HandleValue) {
        if !RejectPromise(cx, self.promise_obj(), value) {
            JS_ClearPendingException(cx);
        }
    }

    #[allow(unsafe_code)]
    pub fn is_fulfilled(&self) -> bool {
        let state = unsafe { GetPromiseState(self.promise_obj()) };
        match state {
            PromiseState::Rejected | PromiseState::Fulfilled => true,
            _ => false
        }
    }

    #[allow(unsafe_code)]
    fn promise_obj(&self) -> HandleObject {
        let obj = self.reflector().get_jsobject();
        unsafe {
            assert!(IsPromiseObject(obj));
        }
        obj
    }

    #[allow(unsafe_code)]
    pub fn append_native_handler(&self, handler: &PromiseNativeHandler) {
        let cx = self.global().get_cx();
        rooted!(in(cx) let resolve_func =
                create_native_handler_function(cx,
                                               handler.reflector().get_jsobject(),
                                               NativeHandlerTask::Resolve));

        rooted!(in(cx) let reject_func =
                create_native_handler_function(cx,
                                               handler.reflector().get_jsobject(),
                                               NativeHandlerTask::Reject));

        unsafe {
            let ok = AddPromiseReactions(cx,
                                         self.promise_obj(),
                                         resolve_func.handle(),
                                         reject_func.handle());
            assert!(ok);
        }
    }
}

#[allow(unsafe_code)]
unsafe extern fn do_nothing_promise_executor(_cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
    let args = CallArgs::from_vp(vp, argc);
    *args.rval() = UndefinedValue();
    true
}

const SLOT_NATIVEHANDLER: usize = 0;
const SLOT_NATIVEHANDLER_TASK: usize = 1;

#[derive(PartialEq)]
enum NativeHandlerTask {
    Resolve = 0,
    Reject = 1,
}

#[allow(unsafe_code)]
unsafe extern fn native_handler_callback(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
    let args = CallArgs::from_vp(vp, argc);
    rooted!(in(cx) let v = *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER));
    assert!(v.get().is_object());

    let handler = root_from_object::<PromiseNativeHandler>(v.to_object())
        .expect("unexpected value for native handler in promise native handler callback");

    rooted!(in(cx) let v = *GetFunctionNativeReserved(args.callee(), SLOT_NATIVEHANDLER_TASK));
    match v.to_int32() {
        v if v == NativeHandlerTask::Resolve as i32 => handler.resolved_callback(cx, args.get(0)),
        v if v == NativeHandlerTask::Reject as i32 => handler.rejected_callback(cx, args.get(0)),
        _ => panic!("unexpected native handler task value"),
    };

    true
}

#[allow(unsafe_code)]
fn create_native_handler_function(cx: *mut JSContext,
                                  holder: HandleObject,
                                  task: NativeHandlerTask) -> *mut JSObject {
    unsafe {
        let func = NewFunctionWithReserved(cx, Some(native_handler_callback), 1, 0, ptr::null());
        assert!(!func.is_null());

        rooted!(in(cx) let obj = JS_GetFunctionObject(func));
        assert!(!obj.is_null());
        SetFunctionNativeReserved(obj.get(),
                                  SLOT_NATIVEHANDLER,
                                  &ObjectValue(*holder));
        SetFunctionNativeReserved(obj.get(),
                                  SLOT_NATIVEHANDLER_TASK,
                                  &Int32Value(task as i32));
        obj.get()
    }
}

<|endoftext|>


<commit_before>use crate::common::verify_bitfield_length;
use types::*;

/// Returns validator indices which participated in the attestation.
///
/// Spec v0.5.1
pub fn get_attestation_participants<T: EthSpec>(
    state: &BeaconState<T>,
    attestation_data: &AttestationData,
    bitfield: &Bitfield,
    spec: &ChainSpec,
) -> Result<Vec<usize>, BeaconStateError> {
    let epoch = attestation_data.slot.epoch(spec.slots_per_epoch);

    let crosslink_committee =
        state.get_crosslink_committee_for_shard(epoch, attestation_data.shard, spec)?;

    if crosslink_committee.slot != attestation_data.slot {
        return Err(BeaconStateError::NoCommitteeForShard);
    }

    let committee = &crosslink_committee.committee;

    if !verify_bitfield_length(&bitfield, committee.len()) {
        return Err(BeaconStateError::InvalidBitfield);
    }

    let mut participants = Vec::with_capacity(committee.len());
    for (i, validator_index) in committee.iter().enumerate() {
        match bitfield.get(i) {
            Ok(bit) if bit => participants.push(*validator_index),
            _ => {}
        }
    }
    participants.shrink_to_fit();

    Ok(participants)
}
<commit_msg>state_processing: delete get_attestation_participants<commit_after><|endoftext|>


<commit_before>// Copyright © 2018, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

#[macro_use]
extern crate slog;
#[macro_use]
extern crate slog_scope;

use cosmogony::{Zone, ZoneIndex};
use failure::Error;
use mimir::objects::Admin;
use mimir::rubber::{IndexSettings, Rubber};
use mimirsbrunn::osm_reader::admin;
use mimirsbrunn::osm_reader::osm_utils;
use mimirsbrunn::utils::normalize_weight;
use std::collections::BTreeMap;
use structopt::StructOpt;

trait IntoAdmin {
    fn into_admin(
        self,
        _: &BTreeMap<ZoneIndex, String>,
        langs: &[String],
        retrocompat_on_french_id: bool,
        max_weight: f64,
    ) -> Admin;
}

fn get_weight(tags: &osmpbfreader::Tags, center_tags: &osmpbfreader::Tags) -> f64 {
    // to have an admin weight we use the osm 'population' tag to priorize
    // the big zones over the small one.
    // Note: this tags is not often filled , so only some zones
    // will have a weight (but the main cities have it).
    tags.get("population")
        .and_then(|p| p.parse().ok())
        .or_else(|| center_tags.get("population")?.parse().ok())
        .unwrap_or(0.)
}

impl IntoAdmin for Zone {
    fn into_admin(
        self,
        zones_osm_id: &BTreeMap<ZoneIndex, String>,
        langs: &[String],
        french_id_retrocompatibility: bool,
        max_weight: f64,
    ) -> Admin {
        let insee = admin::read_insee(&self.tags).unwrap_or("");
        let zip_codes = admin::read_zip_codes(&self.tags);
        let label = self.label;
        let weight = get_weight(&self.tags, &self.center_tags);
        let center = self.center.map_or(mimir::Coord::default(), |c| {
            mimir::Coord::new(c.lng(), c.lat())
        });
        let format_id = |id| {
            if french_id_retrocompatibility && insee != "" {
                // for retrocompatibity reasons, Navitia needs the
                // french admins to have an id with the insee
                format!("admin:fr:{}", insee)
            } else {
                format!("admin:osm:{}", id)
            }
        };
        let parent_osm_id = self
            .parent
            .and_then(|id| zones_osm_id.get(&id))
            .map(format_id);
        Admin {
            id: format_id(&self.osm_id),
            insee: insee.into(),
            level: self.admin_level.unwrap_or(0),
            label: label,
            name: self.name,
            zip_codes: zip_codes,
            weight: normalize_weight(weight, max_weight),
            bbox: self.bbox,
            boundary: self.boundary,
            coord: center,
            zone_type: self.zone_type,
            parent_id: parent_osm_id,
            codes: osm_utils::get_osm_codes_from_tags(&self.tags),
            names: osm_utils::get_names_from_tags(&self.tags, &langs),
            labels: self
                .international_labels
                .into_iter()
                .filter(|(k, _)| langs.contains(&k))
                .collect(),
            distance: None,
        }
    }
}

fn send_to_es(
    admins: impl Iterator<Item = Admin>,
    cnx_string: &str,
    dataset: &str,
    index_settings: IndexSettings,
) -> Result<(), Error> {
    let mut rubber = Rubber::new(cnx_string);
    rubber.initialize_templates()?;
    let nb_admins = rubber.index(dataset, &index_settings, admins)?;
    info!("{} admins added.", nb_admins);
    Ok(())
}

fn read_zones(input: &str) -> Result<impl Iterator<Item = Zone>, Error> {
    Ok(cosmogony::read_zones_from_file(input)?.filter_map(|r| {
        r.map_err(|e| log::warn!("impossible to read zone: {}", e))
            .ok()
    }))
}

fn index_cosmogony(args: Args) -> Result<(), Error> {
    info!("building maps");

    let mut max_weight = 1.0;
    let mut cosmogony_id_to_osm_id = BTreeMap::new();
    for z in read_zones(&args.input)? {
        max_weight = f64::max(max_weight, get_weight(&z.tags, &z.center_tags));
        cosmogony_id_to_osm_id.insert(z.id.clone(), z.osm_id.clone());
    }
    let max_weight = max_weight;
    let cosmogony_id_to_osm_id = cosmogony_id_to_osm_id;

    info!("importing cosmogony into Mimir");
    let admins = read_zones(&args.input)?.map(|z| {
        z.into_admin(
            &cosmogony_id_to_osm_id,
            &args.langs,
            args.french_id_retrocompatibility,
            max_weight,
        )
    });

    let index_settings = IndexSettings {
        nb_shards: args.nb_shards,
        nb_replicas: args.nb_replicas,
    };
    send_to_es(
        admins,
        &args.connection_string,
        &args.dataset,
        index_settings,
    )?;

    Ok(())
}

#[derive(StructOpt, Debug)]
struct Args {
    /// cosmogony file
    #[structopt(short = "i", long = "input")]
    input: String,
    /// Elasticsearch parameters.
    #[structopt(
        short = "c",
        long = "connection-string",
        default_value = "http://localhost:9200/munin"
    )]
    connection_string: String,
    /// Name of the dataset.
    #[structopt(short = "d", long = "dataset", default_value = "fr")]
    dataset: String,
    /// Number of shards for the es index
    #[structopt(short = "s", long = "nb-shards", default_value = "1")]
    nb_shards: usize,
    /// Number of replicas for the es index
    #[structopt(short = "r", long = "nb-replicas", default_value = "1")]
    nb_replicas: usize,
    /// Languages codes, used to build i18n names and labels
    #[structopt(name = "lang", short, long)]
    langs: Vec<String>,
    /// Retrocompatibiilty on french admin id
    /// if activated, the french administrative regions will have an id like 'admin:fr:{insee}'
    /// instead of 'admin:osm:{osm_id}'
    #[structopt(long = "french-id-retrocompatibility")]
    french_id_retrocompatibility: bool,
}

fn main() {
    mimirsbrunn::utils::launch_run(index_cosmogony);
}
<commit_msg>fix infinite loop while loading cosmogony<commit_after>// Copyright © 2018, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

#[macro_use]
extern crate slog;
#[macro_use]
extern crate slog_scope;

use cosmogony::{Zone, ZoneIndex};
use failure::Error;
use mimir::objects::Admin;
use mimir::rubber::{IndexSettings, Rubber};
use mimirsbrunn::osm_reader::admin;
use mimirsbrunn::osm_reader::osm_utils;
use mimirsbrunn::utils::normalize_weight;
use std::collections::BTreeMap;
use structopt::StructOpt;

trait IntoAdmin {
    fn into_admin(
        self,
        _: &BTreeMap<ZoneIndex, (String, Option<String>)>,
        langs: &[String],
        retrocompat_on_french_id: bool,
        max_weight: f64,
    ) -> Admin;
}

fn get_weight(tags: &osmpbfreader::Tags, center_tags: &osmpbfreader::Tags) -> f64 {
    // to have an admin weight we use the osm 'population' tag to priorize
    // the big zones over the small one.
    // Note: this tags is not often filled , so only some zones
    // will have a weight (but the main cities have it).
    tags.get("population")
        .and_then(|p| p.parse().ok())
        .or_else(|| center_tags.get("population")?.parse().ok())
        .unwrap_or(0.)
}

impl IntoAdmin for Zone {
    fn into_admin(
        self,
        zones_osm_id: &BTreeMap<ZoneIndex, (String, Option<String>)>,
        langs: &[String],
        french_id_retrocompatibility: bool,
        max_weight: f64,
    ) -> Admin {
        let insee = admin::read_insee(&self.tags).map(|s| s.to_owned());
        let zip_codes = admin::read_zip_codes(&self.tags);
        let label = self.label;
        let weight = get_weight(&self.tags, &self.center_tags);
        let center = self.center.map_or(mimir::Coord::default(), |c| {
            mimir::Coord::new(c.lng(), c.lat())
        });
        let format_id = |id, insee| {
            // for retrocompatibity reasons, Navitia needs the
            // french admins to have an id with the insee
            match insee {
                Some(insee) if french_id_retrocompatibility => format!("admin:fr:{}", insee),
                _ => format!("admin:osm:{}", id),
            }
        };
        let parent_osm_id = self
            .parent
            .and_then(|id| zones_osm_id.get(&id))
            .map(|(id, insee)| format_id(id, insee.as_ref()));
        Admin {
            id: format_id(&self.osm_id, insee.as_ref()),
            insee: insee.unwrap_or("".to_owned()),
            level: self.admin_level.unwrap_or(0),
            label: label,
            name: self.name,
            zip_codes: zip_codes,
            weight: normalize_weight(weight, max_weight),
            bbox: self.bbox,
            boundary: self.boundary,
            coord: center,
            zone_type: self.zone_type,
            parent_id: parent_osm_id,
            codes: osm_utils::get_osm_codes_from_tags(&self.tags),
            names: osm_utils::get_names_from_tags(&self.tags, &langs),
            labels: self
                .international_labels
                .into_iter()
                .filter(|(k, _)| langs.contains(&k))
                .collect(),
            distance: None,
        }
    }
}

fn send_to_es(
    admins: impl Iterator<Item = Admin>,
    cnx_string: &str,
    dataset: &str,
    index_settings: IndexSettings,
) -> Result<(), Error> {
    let mut rubber = Rubber::new(cnx_string);
    rubber.initialize_templates()?;
    let nb_admins = rubber.index(dataset, &index_settings, admins)?;
    info!("{} admins added.", nb_admins);
    Ok(())
}

fn read_zones(input: &str) -> Result<impl Iterator<Item = Zone>, Error> {
    Ok(cosmogony::read_zones_from_file(input)?.filter_map(|r| {
        r.map_err(|e| log::warn!("impossible to read zone: {}", e))
            .ok()
    }))
}

fn index_cosmogony(args: Args) -> Result<(), Error> {
    info!("building maps");

    let mut max_weight = 1.0;
    let mut cosmogony_id_to_osm_id = BTreeMap::new();
    for z in read_zones(&args.input)? {
        max_weight = f64::max(max_weight, get_weight(&z.tags, &z.center_tags));
        let insee = admin::read_insee(&z.tags).map(|s| s.to_owned());
        cosmogony_id_to_osm_id.insert(z.id.clone(), (z.osm_id.clone(), insee));
    }
    let max_weight = max_weight;
    let cosmogony_id_to_osm_id = cosmogony_id_to_osm_id;

    info!("importing cosmogony into Mimir");
    let admins = read_zones(&args.input)?.map(|z| {
        z.into_admin(
            &cosmogony_id_to_osm_id,
            &args.langs,
            args.french_id_retrocompatibility,
            max_weight,
        )
    });

    let index_settings = IndexSettings {
        nb_shards: args.nb_shards,
        nb_replicas: args.nb_replicas,
    };
    send_to_es(
        admins,
        &args.connection_string,
        &args.dataset,
        index_settings,
    )?;

    Ok(())
}

#[derive(StructOpt, Debug)]
struct Args {
    /// cosmogony file
    #[structopt(short = "i", long = "input")]
    input: String,
    /// Elasticsearch parameters.
    #[structopt(
        short = "c",
        long = "connection-string",
        default_value = "http://localhost:9200/munin"
    )]
    connection_string: String,
    /// Name of the dataset.
    #[structopt(short = "d", long = "dataset", default_value = "fr")]
    dataset: String,
    /// Number of shards for the es index
    #[structopt(short = "s", long = "nb-shards", default_value = "1")]
    nb_shards: usize,
    /// Number of replicas for the es index
    #[structopt(short = "r", long = "nb-replicas", default_value = "1")]
    nb_replicas: usize,
    /// Languages codes, used to build i18n names and labels
    #[structopt(name = "lang", short, long)]
    langs: Vec<String>,
    /// Retrocompatibiilty on french admin id
    /// if activated, the french administrative regions will have an id like 'admin:fr:{insee}'
    /// instead of 'admin:osm:{osm_id}'
    #[structopt(long = "french-id-retrocompatibility")]
    french_id_retrocompatibility: bool,
}

fn main() {
    mimirsbrunn::utils::launch_run(index_cosmogony);
}
<|endoftext|>


<commit_before>use anime::remote::anilist;
use snafu::{Backtrace, ErrorCompat, GenerateBacktrace, Snafu};
use std::io;
use std::num;
use std::path;
use std::result;
use std::sync::mpsc;

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
pub enum Error {
    #[snafu(display("anime lib error: {}", source))]
    Anime {
        source: anime::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("io error: {}", source))]
    IO {
        source: io::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("file io error at {}: {}", path.display(), source))]
    FileIO {
        path: path::PathBuf,
        source: io::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("dir entry error at {}: {}", dir.display(), source))]
    EntryIO {
        dir: path::PathBuf,
        source: io::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("toml decode error at {}: {}", path.display(), source))]
    TomlDecode {
        path: path::PathBuf,
        source: toml::de::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("toml encode error at {}: {}", path.display(), source))]
    TomlEncode {
        path: path::PathBuf,
        source: toml::ser::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("mpsc channel receive error: {}", source))]
    MPSCRecv {
        source: mpsc::RecvError,
        backtrace: Backtrace,
    },

    #[snafu(display("diesel error: {}", source))]
    Diesel {
        source: diesel::result::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("diesel connection error: {}", source))]
    DieselConnection {
        source: diesel::result::ConnectionError,
        backtrace: Backtrace,
    },

    #[snafu(display("error parsing int: {}", source))]
    ParseNum {
        source: num::ParseIntError,
        backtrace: Backtrace,
    },

    #[snafu(display("no series found on disk matching name: {}", name))]
    NoMatchingSeriesOnDisk { name: String },

    #[snafu(display("{} must be added to the program first\nyou can do this in the TUI by using the add command", name))]
    MustAddSeries { name: String },

    #[snafu(display("path must be a directory"))]
    NotADirectory,

    #[snafu(display("series name must be specified"))]
    MustSpecifySeriesName,

    #[snafu(display("command can only be ran in online mode"))]
    MustRunOnline,

    #[snafu(display("failed to play episode {}: {}", episode, source))]
    FailedToPlayEpisode { episode: u32, source: io::Error },

    #[snafu(display("episode {} not found", episode))]
    EpisodeNotFound { episode: u32 },

    #[snafu(display(
        "need access token for AniList\ngo to {} and specify your token with the -t flag",
        anilist::auth_url(crate::ANILIST_CLIENT_ID)
    ))]
    NeedAniListToken,

    #[snafu(display("no command specified"))]
    NoCommandSpecified,

    #[snafu(display("command not found: {}", command))]
    CommandNotFound { command: String },

    #[snafu(display("{} argument(s) specified, need at least {}", has, need))]
    NotEnoughArguments { has: usize, need: usize },

    #[snafu(display("unknown argument: {}", value))]
    UnknownCmdPromptArg { value: String },

    #[snafu(display("series already exists as {}", name))]
    SeriesAlreadyExists { name: String },

    #[snafu(display("must be online to {}", reason))]
    MustBeOnlineTo { reason: String },

    #[snafu(display("invalid score"))]
    InvalidScore,

    #[snafu(display("since this is a new series, you must specify the series ID\nyou can use the add command in the TUI instead to avoid this"))]
    NewSeriesNeedsID,
}

impl Error {
    pub fn is_file_nonexistant(&self) -> bool {
        match self {
            Error::FileIO { source, .. } => source.kind() == io::ErrorKind::NotFound,
            _ => false,
        }
    }
}

impl From<anime::Error> for Error {
    fn from(source: anime::Error) -> Error {
        Error::Anime {
            source,
            backtrace: Backtrace::generate(),
        }
    }
}

impl From<diesel::result::Error> for Error {
    fn from(source: diesel::result::Error) -> Self {
        Self::Diesel {
            source,
            backtrace: Backtrace::generate(),
        }
    }
}

impl From<diesel::result::ConnectionError> for Error {
    fn from(source: diesel::result::ConnectionError) -> Self {
        Self::DieselConnection {
            source,
            backtrace: Backtrace::generate(),
        }
    }
}

impl From<num::ParseIntError> for Error {
    fn from(source: num::ParseIntError) -> Self {
        Self::ParseNum {
            source,
            backtrace: Backtrace::generate(),
        }
    }
}

pub fn display_error(err: Error) {
    eprintln!("{}", err);

    let mut print_backtrace = true;

    if let Error::Anime { source, .. } = &err {
        if let anime::Error::NeedExistingSeriesData = source {
            eprintln!("run the program with the --prefetch flag first when an internet connection is available");
            print_backtrace = false;
        }
    }

    if !print_backtrace {
        return;
    }

    if let Some(backtrace) = err.backtrace() {
        eprintln!("backtrace:\n{}", backtrace);
    }
}
<commit_msg>anup: Don't add prefix to errors from the anime library<commit_after>use anime::remote::anilist;
use snafu::{Backtrace, ErrorCompat, GenerateBacktrace, Snafu};
use std::io;
use std::num;
use std::path;
use std::result;
use std::sync::mpsc;

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
pub enum Error {
    #[snafu(display("{}", source))]
    Anime {
        source: anime::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("io error: {}", source))]
    IO {
        source: io::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("file io error at {}: {}", path.display(), source))]
    FileIO {
        path: path::PathBuf,
        source: io::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("dir entry error at {}: {}", dir.display(), source))]
    EntryIO {
        dir: path::PathBuf,
        source: io::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("toml decode error at {}: {}", path.display(), source))]
    TomlDecode {
        path: path::PathBuf,
        source: toml::de::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("toml encode error at {}: {}", path.display(), source))]
    TomlEncode {
        path: path::PathBuf,
        source: toml::ser::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("mpsc channel receive error: {}", source))]
    MPSCRecv {
        source: mpsc::RecvError,
        backtrace: Backtrace,
    },

    #[snafu(display("diesel error: {}", source))]
    Diesel {
        source: diesel::result::Error,
        backtrace: Backtrace,
    },

    #[snafu(display("diesel connection error: {}", source))]
    DieselConnection {
        source: diesel::result::ConnectionError,
        backtrace: Backtrace,
    },

    #[snafu(display("error parsing int: {}", source))]
    ParseNum {
        source: num::ParseIntError,
        backtrace: Backtrace,
    },

    #[snafu(display("no series found on disk matching name: {}", name))]
    NoMatchingSeriesOnDisk { name: String },

    #[snafu(display("{} must be added to the program first\nyou can do this in the TUI by using the add command", name))]
    MustAddSeries { name: String },

    #[snafu(display("path must be a directory"))]
    NotADirectory,

    #[snafu(display("series name must be specified"))]
    MustSpecifySeriesName,

    #[snafu(display("command can only be ran in online mode"))]
    MustRunOnline,

    #[snafu(display("failed to play episode {}: {}", episode, source))]
    FailedToPlayEpisode { episode: u32, source: io::Error },

    #[snafu(display("episode {} not found", episode))]
    EpisodeNotFound { episode: u32 },

    #[snafu(display(
        "need access token for AniList\ngo to {} and specify your token with the -t flag",
        anilist::auth_url(crate::ANILIST_CLIENT_ID)
    ))]
    NeedAniListToken,

    #[snafu(display("no command specified"))]
    NoCommandSpecified,

    #[snafu(display("command not found: {}", command))]
    CommandNotFound { command: String },

    #[snafu(display("{} argument(s) specified, need at least {}", has, need))]
    NotEnoughArguments { has: usize, need: usize },

    #[snafu(display("unknown argument: {}", value))]
    UnknownCmdPromptArg { value: String },

    #[snafu(display("series already exists as {}", name))]
    SeriesAlreadyExists { name: String },

    #[snafu(display("must be online to {}", reason))]
    MustBeOnlineTo { reason: String },

    #[snafu(display("invalid score"))]
    InvalidScore,

    #[snafu(display("since this is a new series, you must specify the series ID\nyou can use the add command in the TUI instead to avoid this"))]
    NewSeriesNeedsID,
}

impl Error {
    pub fn is_file_nonexistant(&self) -> bool {
        match self {
            Error::FileIO { source, .. } => source.kind() == io::ErrorKind::NotFound,
            _ => false,
        }
    }
}

impl From<anime::Error> for Error {
    fn from(source: anime::Error) -> Error {
        Error::Anime {
            source,
            backtrace: Backtrace::generate(),
        }
    }
}

impl From<diesel::result::Error> for Error {
    fn from(source: diesel::result::Error) -> Self {
        Self::Diesel {
            source,
            backtrace: Backtrace::generate(),
        }
    }
}

impl From<diesel::result::ConnectionError> for Error {
    fn from(source: diesel::result::ConnectionError) -> Self {
        Self::DieselConnection {
            source,
            backtrace: Backtrace::generate(),
        }
    }
}

impl From<num::ParseIntError> for Error {
    fn from(source: num::ParseIntError) -> Self {
        Self::ParseNum {
            source,
            backtrace: Backtrace::generate(),
        }
    }
}

pub fn display_error(err: Error) {
    eprintln!("{}", err);

    let mut print_backtrace = true;

    if let Error::Anime { source, .. } = &err {
        if let anime::Error::NeedExistingSeriesData = source {
            eprintln!("run the program with the --prefetch flag first when an internet connection is available");
            print_backtrace = false;
        }
    }

    if !print_backtrace {
        return;
    }

    if let Some(backtrace) = err.backtrace() {
        eprintln!("backtrace:\n{}", backtrace);
    }
}
<|endoftext|>


<commit_before>use std::num::{Zero, One};
use traits::basis::Basis;
use traits::cross::Cross;
use traits::division_ring::DivisionRing;
use traits::norm::Norm;
use traits::sample::UniformSphereSample;
use vec::{Vec1, Vec2, Vec3};

impl<N: Mul<N, N> + Sub<N, N>> Cross<Vec1<N>> for Vec2<N>
{
  #[inline]
  fn cross(&self, other : &Vec2<N>) -> Vec1<N>
  { Vec1::new(self.x * other.y - self.y * other.x) }
}

impl<N: Mul<N, N> + Sub<N, N>> Cross<Vec3<N>> for Vec3<N>
{
  #[inline]
  fn cross(&self, other : &Vec3<N>) -> Vec3<N>
  {
    Vec3::new(self.y * other.z - self.z * other.y,
              self.z * other.x - self.x * other.z,
              self.x * other.y - self.y * other.x
    )
  }
}

impl<N: One> Basis for Vec1<N>
{
  #[inline(always)]
  fn canonical_basis(f: &fn(Vec1<N>))
  { f(Vec1::new(One::one())) }

  #[inline(always)]
  fn orthonormal_subspace_basis(&self, _: &fn(Vec1<N>))
  { }
}

impl<N: Clone + One + Zero + Neg<N>> Basis for Vec2<N>
{
  #[inline]
  fn canonical_basis(f: &fn(Vec2<N>))
  {
    f(Vec2::new(One::one(), Zero::zero()));
    f(Vec2::new(Zero::zero(), One::one()));
  }

  #[inline]
  fn orthonormal_subspace_basis(&self, f: &fn(Vec2<N>))
  { f(Vec2::new(-self.y, self.x.clone())) }
}

impl<N: Clone + DivisionRing + Ord + Algebraic + Signed>
Basis for Vec3<N>
{
  #[inline(always)]
  fn canonical_basis(f: &fn(Vec3<N>))
  {
    f(Vec3::new(One::one(), Zero::zero(), Zero::zero()));
    f(Vec3::new(Zero::zero(), One::one(), Zero::zero()));
    f(Vec3::new(Zero::zero(), Zero::zero(), One::one()));
  }

  #[inline(always)]
  fn orthonormal_subspace_basis(&self, f: &fn(Vec3<N>))
  {
      let a =
        if self.x.clone().abs() > self.y.clone().abs()
        { Vec3::new(self.z.clone(), Zero::zero(), -self.x).normalized() }
        else
        { Vec3::new(Zero::zero(), -self.z, self.y.clone()).normalized() };

      f(a.cross(self));
      f(a);
  }
}

// FIXME: this bad: this fixes definitly the number of samples…
static SAMPLES_2_F64: [Vec2<f64>, ..21] = [
  Vec2 { x: 1.0,         y: 0.0         },
  Vec2 { x: 0.95557281,  y: 0.29475517  },
  Vec2 { x: 0.82623877,  y: 0.56332006  },
  Vec2 { x: 0.6234898,   y: 0.78183148  },
  Vec2 { x: 0.36534102,  y: 0.93087375  },
  Vec2 { x: 0.07473009,  y: 0.9972038   },
  Vec2 { x: -0.22252093, y: 0.97492791  },
  Vec2 { x: -0.5,        y: 0.8660254   },
  Vec2 { x: -0.73305187, y: 0.68017274  },
  Vec2 { x: -0.90096887, y: 0.43388374  },
  Vec2 { x: -0.98883083, y: 0.14904227  },
  Vec2 { x: -0.98883083, y: -0.14904227 },
  Vec2 { x: -0.90096887, y: -0.43388374 },
  Vec2 { x: -0.73305187, y: -0.68017274 },
  Vec2 { x: -0.5,        y: -0.8660254  },
  Vec2 { x: -0.22252093, y: -0.97492791 },
  Vec2 { x: 0.07473009,  y: -0.9972038  },
  Vec2 { x: 0.36534102,  y: -0.93087375 },
  Vec2 { x: 0.6234898,   y: -0.78183148 },
  Vec2 { x: 0.82623877,  y: -0.56332006 },
  Vec2 { x: 0.95557281,  y: -0.29475517 },
];

impl UniformSphereSample for Vec2<f64>
{
  pub fn sample(f: &fn(&'static Vec2<f64>))
  {
    for SAMPLES_2_F64.iter().advance |sample|
    { f(sample) }
  }
}

impl UniformSphereSample for Vec3<f64>
{
  pub fn sample(_: &fn(&'static Vec3<f64>))
  {
    fail!("UniformSphereSample for Vec3<f64> is not yet implemented.")
  }
}
<commit_msg>Add sphere sampling implementation for Vec3<f64>.<commit_after>use std::num::{Zero, One};
use traits::basis::Basis;
use traits::cross::Cross;
use traits::division_ring::DivisionRing;
use traits::norm::Norm;
use traits::sample::UniformSphereSample;
use vec::{Vec1, Vec2, Vec3};

impl<N: Mul<N, N> + Sub<N, N>> Cross<Vec1<N>> for Vec2<N>
{
  #[inline]
  fn cross(&self, other : &Vec2<N>) -> Vec1<N>
  { Vec1::new(self.x * other.y - self.y * other.x) }
}

impl<N: Mul<N, N> + Sub<N, N>> Cross<Vec3<N>> for Vec3<N>
{
  #[inline]
  fn cross(&self, other : &Vec3<N>) -> Vec3<N>
  {
    Vec3::new(self.y * other.z - self.z * other.y,
              self.z * other.x - self.x * other.z,
              self.x * other.y - self.y * other.x
    )
  }
}

impl<N: One> Basis for Vec1<N>
{
  #[inline(always)]
  fn canonical_basis(f: &fn(Vec1<N>))
  { f(Vec1::new(One::one())) }

  #[inline(always)]
  fn orthonormal_subspace_basis(&self, _: &fn(Vec1<N>))
  { }
}

impl<N: Clone + One + Zero + Neg<N>> Basis for Vec2<N>
{
  #[inline]
  fn canonical_basis(f: &fn(Vec2<N>))
  {
    f(Vec2::new(One::one(), Zero::zero()));
    f(Vec2::new(Zero::zero(), One::one()));
  }

  #[inline]
  fn orthonormal_subspace_basis(&self, f: &fn(Vec2<N>))
  { f(Vec2::new(-self.y, self.x.clone())) }
}

impl<N: Clone + DivisionRing + Ord + Algebraic + Signed>
Basis for Vec3<N>
{
  #[inline(always)]
  fn canonical_basis(f: &fn(Vec3<N>))
  {
    f(Vec3::new(One::one(), Zero::zero(), Zero::zero()));
    f(Vec3::new(Zero::zero(), One::one(), Zero::zero()));
    f(Vec3::new(Zero::zero(), Zero::zero(), One::one()));
  }

  #[inline(always)]
  fn orthonormal_subspace_basis(&self, f: &fn(Vec3<N>))
  {
      let a =
        if self.x.clone().abs() > self.y.clone().abs()
        { Vec3::new(self.z.clone(), Zero::zero(), -self.x).normalized() }
        else
        { Vec3::new(Zero::zero(), -self.z, self.y.clone()).normalized() };

      f(a.cross(self));
      f(a);
  }
}

// FIXME: this bad: this fixes definitly the number of samples…
static SAMPLES_2_F64: [Vec2<f64>, ..21] = [
  Vec2 { x: 1.0,         y: 0.0         },
  Vec2 { x: 0.95557281,  y: 0.29475517  },
  Vec2 { x: 0.82623877,  y: 0.56332006  },
  Vec2 { x: 0.6234898,   y: 0.78183148  },
  Vec2 { x: 0.36534102,  y: 0.93087375  },
  Vec2 { x: 0.07473009,  y: 0.9972038   },
  Vec2 { x: -0.22252093, y: 0.97492791  },
  Vec2 { x: -0.5,        y: 0.8660254   },
  Vec2 { x: -0.73305187, y: 0.68017274  },
  Vec2 { x: -0.90096887, y: 0.43388374  },
  Vec2 { x: -0.98883083, y: 0.14904227  },
  Vec2 { x: -0.98883083, y: -0.14904227 },
  Vec2 { x: -0.90096887, y: -0.43388374 },
  Vec2 { x: -0.73305187, y: -0.68017274 },
  Vec2 { x: -0.5,        y: -0.8660254  },
  Vec2 { x: -0.22252093, y: -0.97492791 },
  Vec2 { x: 0.07473009,  y: -0.9972038  },
  Vec2 { x: 0.36534102,  y: -0.93087375 },
  Vec2 { x: 0.6234898,   y: -0.78183148 },
  Vec2 { x: 0.82623877,  y: -0.56332006 },
  Vec2 { x: 0.95557281,  y: -0.29475517 },
];

// Those vectors come from bullet 3d
static SAMPLES_3_F64: [Vec3<f64>, ..42] = [
  Vec3 { x: 0.000000 , y: -0.000000, z: -1.000000 },
  Vec3 { x: 0.723608 , y: -0.525725, z: -0.447219 },
  Vec3 { x: -0.276388, y: -0.850649, z: -0.447219 },
  Vec3 { x: -0.894426, y: -0.000000, z: -0.447216 },
  Vec3 { x: -0.276388, y: 0.850649 , z: -0.447220 },
  Vec3 { x: 0.723608 , y: 0.525725 , z: -0.447219 },
  Vec3 { x: 0.276388 , y: -0.850649, z: 0.447220 },
  Vec3 { x: -0.723608, y: -0.525725, z: 0.447219 },
  Vec3 { x: -0.723608, y: 0.525725 , z: 0.447219 },
  Vec3 { x: 0.276388 , y: 0.850649 , z: 0.447219 },
  Vec3 { x: 0.894426 , y: 0.000000 , z: 0.447216 },
  Vec3 { x: -0.000000, y: 0.000000 , z: 1.000000 },
  Vec3 { x: 0.425323 , y: -0.309011, z: -0.850654 },
  Vec3 { x: -0.162456, y: -0.499995, z: -0.850654 },
  Vec3 { x: 0.262869 , y: -0.809012, z: -0.525738 },
  Vec3 { x: 0.425323 , y: 0.309011 , z: -0.850654 },
  Vec3 { x: 0.850648 , y: -0.000000, z: -0.525736 },
  Vec3 { x: -0.525730, y: -0.000000, z: -0.850652 },
  Vec3 { x: -0.688190, y: -0.499997, z: -0.525736 },
  Vec3 { x: -0.162456, y: 0.499995 , z: -0.850654 },
  Vec3 { x: -0.688190, y: 0.499997 , z: -0.525736 },
  Vec3 { x: 0.262869 , y: 0.809012 , z: -0.525738 },
  Vec3 { x: 0.951058 , y: 0.309013 , z: 0.000000 },
  Vec3 { x: 0.951058 , y: -0.309013, z: 0.000000 },
  Vec3 { x: 0.587786 , y: -0.809017, z: 0.000000 },
  Vec3 { x: 0.000000 , y: -1.000000, z: 0.000000 },
  Vec3 { x: -0.587786, y: -0.809017, z: 0.000000 },
  Vec3 { x: -0.951058, y: -0.309013, z: -0.000000 },
  Vec3 { x: -0.951058, y: 0.309013 , z: -0.000000 },
  Vec3 { x: -0.587786, y: 0.809017 , z: -0.000000 },
  Vec3 { x: -0.000000, y: 1.000000 , z: -0.000000 },
  Vec3 { x: 0.587786 , y: 0.809017 , z: -0.000000 },
  Vec3 { x: 0.688190 , y: -0.499997, z: 0.525736 },
  Vec3 { x: -0.262869, y: -0.809012, z: 0.525738 },
  Vec3 { x: -0.850648, y: 0.000000 , z: 0.525736 },
  Vec3 { x: -0.262869, y: 0.809012 , z: 0.525738 },
  Vec3 { x: 0.688190 , y: 0.499997 , z: 0.525736 },
  Vec3 { x: 0.525730 , y: 0.000000 , z: 0.850652 },
  Vec3 { x: 0.162456 , y: -0.499995, z: 0.850654 },
  Vec3 { x: -0.425323, y: -0.309011, z: 0.850654 },
  Vec3 { x: -0.425323, y: 0.309011 , z: 0.850654 },
  Vec3 { x: 0.162456 , y: 0.499995 , z: 0.850654 }
];

impl UniformSphereSample for Vec2<f64>
{
  pub fn sample(f: &fn(&'static Vec2<f64>))
  {
    for SAMPLES_2_F64.iter().advance |sample|
    { f(sample) }
  }
}

impl UniformSphereSample for Vec3<f64>
{
  pub fn sample(f: &fn(&'static Vec3<f64>))
  {
    for SAMPLES_3_F64.iter().advance |sample|
    { f(sample) }
  }
}
<|endoftext|>