<commit_before>use crate::borrow_check::place_ext::PlaceExt;
use crate::borrow_check::nll::ToRegionVid;
use crate::dataflow::indexes::BorrowIndex;
use crate::dataflow::move_paths::MoveData;
use rustc::mir::traversal;
use rustc::mir::visit::{PlaceContext, Visitor, NonUseContext, MutatingUseContext};
use rustc::mir::{self, Location, Mir, Local};
use rustc::ty::{RegionVid, TyCtxt};
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::bit_set::BitSet;
use std::fmt;
use std::ops::Index;

crate struct BorrowSet<'tcx> {
    /// The fundamental map relating bitvector indexes to the borrows
    /// in the MIR.
    crate borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,

    /// Each borrow is also uniquely identified in the MIR by the
    /// `Location` of the assignment statement in which it appears on
    /// the right hand side; we map each such location to the
    /// corresponding `BorrowIndex`.
    crate location_map: FxHashMap<Location, BorrowIndex>,

    /// Locations which activate borrows.
    /// NOTE: a given location may activate more than one borrow in the future
    /// when more general two-phase borrow support is introduced, but for now we
    /// only need to store one borrow index.
    crate activation_map: FxHashMap<Location, Vec<BorrowIndex>>,

    /// Map from local to all the borrows on that local.
    crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,

    crate locals_state_at_exit: LocalsStateAtExit,
}

impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
    type Output = BorrowData<'tcx>;

    fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> {
        &self.borrows[index]
    }
}

/// Location where a two-phase borrow is activated, if a borrow
/// is in fact a two-phase borrow.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
crate enum TwoPhaseActivation {
    NotTwoPhase,
    NotActivated,
    ActivatedAt(Location),
}

#[derive(Debug, Clone)]
crate struct BorrowData<'tcx> {
    /// Location where the borrow reservation starts.
    /// In many cases, this will be equal to the activation location but not always.
    crate reserve_location: Location,
    /// Location where the borrow is activated.
    crate activation_location: TwoPhaseActivation,
    /// What kind of borrow this is
    crate kind: mir::BorrowKind,
    /// The region for which this borrow is live
    crate region: RegionVid,
    /// Place from which we are borrowing
    crate borrowed_place: mir::Place<'tcx>,
    /// Place to which the borrow was stored
    crate assigned_place: mir::Place<'tcx>,
}

impl<'tcx> fmt::Display for BorrowData<'tcx> {
    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
        let kind = match self.kind {
            mir::BorrowKind::Shared => "",
            mir::BorrowKind::Shallow => "shallow ",
            mir::BorrowKind::Unique => "uniq ",
            mir::BorrowKind::Mut { .. } => "mut ",
        };
        write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place)
    }
}

crate enum LocalsStateAtExit {
    AllAreInvalidated,
    SomeAreInvalidated { has_storage_dead_or_moved: BitSet<Local> }
}

impl LocalsStateAtExit {
    fn build(
        locals_are_invalidated_at_exit: bool,
        mir: &Mir<'tcx>,
        move_data: &MoveData<'tcx>
    ) -> Self {
        struct HasStorageDead(BitSet<Local>);

        impl<'tcx> Visitor<'tcx> for HasStorageDead {
            fn visit_local(&mut self, local: &Local, ctx: PlaceContext<'tcx>, _: Location) {
                if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) {
                    self.0.insert(*local);
                }
            }
        }

        if locals_are_invalidated_at_exit {
            LocalsStateAtExit::AllAreInvalidated
        } else {
            let mut has_storage_dead = HasStorageDead(BitSet::new_empty(mir.local_decls.len()));
            has_storage_dead.visit_mir(mir);
            let mut has_storage_dead_or_moved = has_storage_dead.0;
            for move_out in &move_data.moves {
                if let Some(index) = move_data.base_local(move_out.path) {
                    has_storage_dead_or_moved.insert(index);

                }
            }
            LocalsStateAtExit::SomeAreInvalidated{ has_storage_dead_or_moved }
        }
    }
}

impl<'tcx> BorrowSet<'tcx> {
    pub fn build(
        tcx: TyCtxt<'_, '_, 'tcx>,
        mir: &Mir<'tcx>,
        locals_are_invalidated_at_exit: bool,
        move_data: &MoveData<'tcx>
    ) -> Self {

        let mut visitor = GatherBorrows {
            tcx,
            mir,
            idx_vec: IndexVec::new(),
            location_map: Default::default(),
            activation_map: Default::default(),
            local_map: Default::default(),
            pending_activations: Default::default(),
            locals_state_at_exit:
                LocalsStateAtExit::build(locals_are_invalidated_at_exit, mir, move_data),
        };

        for (block, block_data) in traversal::preorder(mir) {
            visitor.visit_basic_block_data(block, block_data);
        }

        BorrowSet {
            borrows: visitor.idx_vec,
            location_map: visitor.location_map,
            activation_map: visitor.activation_map,
            local_map: visitor.local_map,
            locals_state_at_exit: visitor.locals_state_at_exit,
        }
    }

    crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] {
        self.activation_map
            .get(&location)
            .map(|activations| &activations[..])
            .unwrap_or(&[])
    }
}

struct GatherBorrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'gcx, 'tcx>,
    mir: &'a Mir<'tcx>,
    idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
    location_map: FxHashMap<Location, BorrowIndex>,
    activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
    local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,

    /// When we encounter a 2-phase borrow statement, it will always
    /// be assigning into a temporary TEMP:
    ///
    ///    TEMP = &foo
    ///
    /// We add TEMP into this map with `b`, where `b` is the index of
    /// the borrow. When we find a later use of this activation, we
    /// remove from the map (and add to the "tombstone" set below).
    pending_activations: FxHashMap<mir::Local, BorrowIndex>,

    locals_state_at_exit: LocalsStateAtExit,
}

impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
    fn visit_assign(
        &mut self,
        block: mir::BasicBlock,
        assigned_place: &mir::Place<'tcx>,
        rvalue: &mir::Rvalue<'tcx>,
        location: mir::Location,
    ) {
        if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue {
            if borrowed_place.ignore_borrow(
                self.tcx, self.mir, &self.locals_state_at_exit) {
                return;
            }

            let region = region.to_region_vid();

            let borrow = BorrowData {
                kind,
                region,
                reserve_location: location,
                activation_location: TwoPhaseActivation::NotTwoPhase,
                borrowed_place: borrowed_place.clone(),
                assigned_place: assigned_place.clone(),
            };
            let idx = self.idx_vec.push(borrow);
            self.location_map.insert(location, idx);

            self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx);

            if let Some(local) = borrowed_place.root_local() {
                self.local_map.entry(local).or_default().insert(idx);
            }
        }

        self.super_assign(block, assigned_place, rvalue, location)
    }

    fn visit_local(
        &mut self,
        temp: &Local,
        context: PlaceContext<'tcx>,
        location: Location,
    ) {
        if !context.is_use() {
            return;
        }

        // We found a use of some temporary TMP
        // check whether we (earlier) saw a 2-phase borrow like
        //
        //     TMP = &mut place
        if let Some(&borrow_index) = self.pending_activations.get(temp) {
            let borrow_data = &mut self.idx_vec[borrow_index];

            // Watch out: the use of TMP in the borrow itself
            // doesn't count as an activation. =)
            if borrow_data.reserve_location == location &&
                context == PlaceContext::MutatingUse(MutatingUseContext::Store)
            {
                return;
            }

            if let TwoPhaseActivation::ActivatedAt(other_location) =
                    borrow_data.activation_location {
                span_bug!(
                    self.mir.source_info(location).span,
                    "found two uses for 2-phase borrow temporary {:?}: \
                     {:?} and {:?}",
                    temp,
                    location,
                    other_location,
                );
            }

            // Otherwise, this is the unique later use that we expect.
            // Double check: This borrow is indeed a two-phase borrow (that is,
            // we are 'transitioning' from `NotActivated` to `ActivatedAt`) and
            // we've not found any other activations (checked above).
            assert_eq!(
                borrow_data.activation_location,
                TwoPhaseActivation::NotActivated,
                "never found an activation for this borrow!",
            );
            self.activation_map
                .entry(location)
                .or_default()
                .push(borrow_index);

            borrow_data.activation_location = TwoPhaseActivation::ActivatedAt(location);
        }
    }

    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) {
        if let mir::Rvalue::Ref(region, kind, ref place) = *rvalue {
            // double-check that we already registered a BorrowData for this

            let borrow_index = self.location_map[&location];
            let borrow_data = &self.idx_vec[borrow_index];
            assert_eq!(borrow_data.reserve_location, location);
            assert_eq!(borrow_data.kind, kind);
            assert_eq!(borrow_data.region, region.to_region_vid());
            assert_eq!(borrow_data.borrowed_place, *place);
        }

        return self.super_rvalue(rvalue, location);
    }

    fn visit_statement(
        &mut self,
        block: mir::BasicBlock,
        statement: &mir::Statement<'tcx>,
        location: Location,
    ) {
        return self.super_statement(block, statement, location);
    }
}

impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> {
    /// Returns `true` if the borrow represented by `kind` is
    /// allowed to be split into separate Reservation and
    /// Activation phases.
    fn allow_two_phase_borrow(&self, kind: mir::BorrowKind) -> bool {
        kind.allows_two_phase_borrow()
    }

    /// If this is a two-phase borrow, then we will record it
    /// as "pending" until we find the activating use.
    fn insert_as_pending_if_two_phase(
        &mut self,
        start_location: Location,
        assigned_place: &mir::Place<'tcx>,
        kind: mir::BorrowKind,
        borrow_index: BorrowIndex,
    ) {
        debug!(
            "Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?})",
            start_location, assigned_place, borrow_index,
        );

        if !self.allow_two_phase_borrow(kind) {
            debug!("  -> {:?}", start_location);
            return;
        }

        // When we encounter a 2-phase borrow statement, it will always
        // be assigning into a temporary TEMP:
        //
        //    TEMP = &foo
        //
        // so extract `temp`.
        let temp = if let &mir::Place::Base(mir::PlaceBase::Local(temp)) = assigned_place {
            temp
        } else {
            span_bug!(
                self.mir.source_info(start_location).span,
                "expected 2-phase borrow to assign to a local, not `{:?}`",
                assigned_place,
            );
        };

        // Consider the borrow not activated to start. When we find an activation, we'll update
        // this field.
        {
            let borrow_data = &mut self.idx_vec[borrow_index];
            borrow_data.activation_location = TwoPhaseActivation::NotActivated;
        }

        // Insert `temp` into the list of pending activations. From
        // now on, we'll be on the lookout for a use of it. Note that
        // we are guaranteed that this use will come after the
        // assignment.
        let old_value = self.pending_activations.insert(temp, borrow_index);
        if let Some(old_index) = old_value {
            span_bug!(self.mir.source_info(start_location).span,
                      "found already pending activation for temp: {:?} \
                       at borrow_index: {:?} with associated data {:?}",
                      temp, old_index, self.idx_vec[old_index]);
        }
    }
}
<commit_msg>Remove unnecessary function<commit_after>use crate::borrow_check::place_ext::PlaceExt;
use crate::borrow_check::nll::ToRegionVid;
use crate::borrow_check::path_utils::allow_two_phase_borrow;
use crate::dataflow::indexes::BorrowIndex;
use crate::dataflow::move_paths::MoveData;
use rustc::mir::traversal;
use rustc::mir::visit::{PlaceContext, Visitor, NonUseContext, MutatingUseContext};
use rustc::mir::{self, Location, Mir, Local};
use rustc::ty::{RegionVid, TyCtxt};
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::bit_set::BitSet;
use std::fmt;
use std::ops::Index;

crate struct BorrowSet<'tcx> {
    /// The fundamental map relating bitvector indexes to the borrows
    /// in the MIR.
    crate borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,

    /// Each borrow is also uniquely identified in the MIR by the
    /// `Location` of the assignment statement in which it appears on
    /// the right hand side; we map each such location to the
    /// corresponding `BorrowIndex`.
    crate location_map: FxHashMap<Location, BorrowIndex>,

    /// Locations which activate borrows.
    /// NOTE: a given location may activate more than one borrow in the future
    /// when more general two-phase borrow support is introduced, but for now we
    /// only need to store one borrow index.
    crate activation_map: FxHashMap<Location, Vec<BorrowIndex>>,

    /// Map from local to all the borrows on that local.
    crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,

    crate locals_state_at_exit: LocalsStateAtExit,
}

impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
    type Output = BorrowData<'tcx>;

    fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> {
        &self.borrows[index]
    }
}

/// Location where a two-phase borrow is activated, if a borrow
/// is in fact a two-phase borrow.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
crate enum TwoPhaseActivation {
    NotTwoPhase,
    NotActivated,
    ActivatedAt(Location),
}

#[derive(Debug, Clone)]
crate struct BorrowData<'tcx> {
    /// Location where the borrow reservation starts.
    /// In many cases, this will be equal to the activation location but not always.
    crate reserve_location: Location,
    /// Location where the borrow is activated.
    crate activation_location: TwoPhaseActivation,
    /// What kind of borrow this is
    crate kind: mir::BorrowKind,
    /// The region for which this borrow is live
    crate region: RegionVid,
    /// Place from which we are borrowing
    crate borrowed_place: mir::Place<'tcx>,
    /// Place to which the borrow was stored
    crate assigned_place: mir::Place<'tcx>,
}

impl<'tcx> fmt::Display for BorrowData<'tcx> {
    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
        let kind = match self.kind {
            mir::BorrowKind::Shared => "",
            mir::BorrowKind::Shallow => "shallow ",
            mir::BorrowKind::Unique => "uniq ",
            mir::BorrowKind::Mut { .. } => "mut ",
        };
        write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place)
    }
}

crate enum LocalsStateAtExit {
    AllAreInvalidated,
    SomeAreInvalidated { has_storage_dead_or_moved: BitSet<Local> }
}

impl LocalsStateAtExit {
    fn build(
        locals_are_invalidated_at_exit: bool,
        mir: &Mir<'tcx>,
        move_data: &MoveData<'tcx>
    ) -> Self {
        struct HasStorageDead(BitSet<Local>);

        impl<'tcx> Visitor<'tcx> for HasStorageDead {
            fn visit_local(&mut self, local: &Local, ctx: PlaceContext<'tcx>, _: Location) {
                if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) {
                    self.0.insert(*local);
                }
            }
        }

        if locals_are_invalidated_at_exit {
            LocalsStateAtExit::AllAreInvalidated
        } else {
            let mut has_storage_dead = HasStorageDead(BitSet::new_empty(mir.local_decls.len()));
            has_storage_dead.visit_mir(mir);
            let mut has_storage_dead_or_moved = has_storage_dead.0;
            for move_out in &move_data.moves {
                if let Some(index) = move_data.base_local(move_out.path) {
                    has_storage_dead_or_moved.insert(index);

                }
            }
            LocalsStateAtExit::SomeAreInvalidated{ has_storage_dead_or_moved }
        }
    }
}

impl<'tcx> BorrowSet<'tcx> {
    pub fn build(
        tcx: TyCtxt<'_, '_, 'tcx>,
        mir: &Mir<'tcx>,
        locals_are_invalidated_at_exit: bool,
        move_data: &MoveData<'tcx>
    ) -> Self {

        let mut visitor = GatherBorrows {
            tcx,
            mir,
            idx_vec: IndexVec::new(),
            location_map: Default::default(),
            activation_map: Default::default(),
            local_map: Default::default(),
            pending_activations: Default::default(),
            locals_state_at_exit:
                LocalsStateAtExit::build(locals_are_invalidated_at_exit, mir, move_data),
        };

        for (block, block_data) in traversal::preorder(mir) {
            visitor.visit_basic_block_data(block, block_data);
        }

        BorrowSet {
            borrows: visitor.idx_vec,
            location_map: visitor.location_map,
            activation_map: visitor.activation_map,
            local_map: visitor.local_map,
            locals_state_at_exit: visitor.locals_state_at_exit,
        }
    }

    crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] {
        self.activation_map
            .get(&location)
            .map(|activations| &activations[..])
            .unwrap_or(&[])
    }
}

struct GatherBorrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'gcx, 'tcx>,
    mir: &'a Mir<'tcx>,
    idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
    location_map: FxHashMap<Location, BorrowIndex>,
    activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
    local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,

    /// When we encounter a 2-phase borrow statement, it will always
    /// be assigning into a temporary TEMP:
    ///
    ///    TEMP = &foo
    ///
    /// We add TEMP into this map with `b`, where `b` is the index of
    /// the borrow. When we find a later use of this activation, we
    /// remove from the map (and add to the "tombstone" set below).
    pending_activations: FxHashMap<mir::Local, BorrowIndex>,

    locals_state_at_exit: LocalsStateAtExit,
}

impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
    fn visit_assign(
        &mut self,
        block: mir::BasicBlock,
        assigned_place: &mir::Place<'tcx>,
        rvalue: &mir::Rvalue<'tcx>,
        location: mir::Location,
    ) {
        if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue {
            if borrowed_place.ignore_borrow(
                self.tcx, self.mir, &self.locals_state_at_exit) {
                return;
            }

            let region = region.to_region_vid();

            let borrow = BorrowData {
                kind,
                region,
                reserve_location: location,
                activation_location: TwoPhaseActivation::NotTwoPhase,
                borrowed_place: borrowed_place.clone(),
                assigned_place: assigned_place.clone(),
            };
            let idx = self.idx_vec.push(borrow);
            self.location_map.insert(location, idx);

            self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx);

            if let Some(local) = borrowed_place.root_local() {
                self.local_map.entry(local).or_default().insert(idx);
            }
        }

        self.super_assign(block, assigned_place, rvalue, location)
    }

    fn visit_local(
        &mut self,
        temp: &Local,
        context: PlaceContext<'tcx>,
        location: Location,
    ) {
        if !context.is_use() {
            return;
        }

        // We found a use of some temporary TMP
        // check whether we (earlier) saw a 2-phase borrow like
        //
        //     TMP = &mut place
        if let Some(&borrow_index) = self.pending_activations.get(temp) {
            let borrow_data = &mut self.idx_vec[borrow_index];

            // Watch out: the use of TMP in the borrow itself
            // doesn't count as an activation. =)
            if borrow_data.reserve_location == location &&
                context == PlaceContext::MutatingUse(MutatingUseContext::Store)
            {
                return;
            }

            if let TwoPhaseActivation::ActivatedAt(other_location) =
                    borrow_data.activation_location {
                span_bug!(
                    self.mir.source_info(location).span,
                    "found two uses for 2-phase borrow temporary {:?}: \
                     {:?} and {:?}",
                    temp,
                    location,
                    other_location,
                );
            }

            // Otherwise, this is the unique later use that we expect.
            // Double check: This borrow is indeed a two-phase borrow (that is,
            // we are 'transitioning' from `NotActivated` to `ActivatedAt`) and
            // we've not found any other activations (checked above).
            assert_eq!(
                borrow_data.activation_location,
                TwoPhaseActivation::NotActivated,
                "never found an activation for this borrow!",
            );
            self.activation_map
                .entry(location)
                .or_default()
                .push(borrow_index);

            borrow_data.activation_location = TwoPhaseActivation::ActivatedAt(location);
        }
    }

    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) {
        if let mir::Rvalue::Ref(region, kind, ref place) = *rvalue {
            // double-check that we already registered a BorrowData for this

            let borrow_index = self.location_map[&location];
            let borrow_data = &self.idx_vec[borrow_index];
            assert_eq!(borrow_data.reserve_location, location);
            assert_eq!(borrow_data.kind, kind);
            assert_eq!(borrow_data.region, region.to_region_vid());
            assert_eq!(borrow_data.borrowed_place, *place);
        }

        return self.super_rvalue(rvalue, location);
    }

    fn visit_statement(
        &mut self,
        block: mir::BasicBlock,
        statement: &mir::Statement<'tcx>,
        location: Location,
    ) {
        return self.super_statement(block, statement, location);
    }
}

impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> {

    /// If this is a two-phase borrow, then we will record it
    /// as "pending" until we find the activating use.
    fn insert_as_pending_if_two_phase(
        &mut self,
        start_location: Location,
        assigned_place: &mir::Place<'tcx>,
        kind: mir::BorrowKind,
        borrow_index: BorrowIndex,
    ) {
        debug!(
            "Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?})",
            start_location, assigned_place, borrow_index,
        );

        if !allow_two_phase_borrow(&self.tcx, kind) {
            debug!("  -> {:?}", start_location);
            return;
        }

        // When we encounter a 2-phase borrow statement, it will always
        // be assigning into a temporary TEMP:
        //
        //    TEMP = &foo
        //
        // so extract `temp`.
        let temp = if let &mir::Place::Base(mir::PlaceBase::Local(temp)) = assigned_place {
            temp
        } else {
            span_bug!(
                self.mir.source_info(start_location).span,
                "expected 2-phase borrow to assign to a local, not `{:?}`",
                assigned_place,
            );
        };

        // Consider the borrow not activated to start. When we find an activation, we'll update
        // this field.
        {
            let borrow_data = &mut self.idx_vec[borrow_index];
            borrow_data.activation_location = TwoPhaseActivation::NotActivated;
        }

        // Insert `temp` into the list of pending activations. From
        // now on, we'll be on the lookout for a use of it. Note that
        // we are guaranteed that this use will come after the
        // assignment.
        let old_value = self.pending_activations.insert(temp, borrow_index);
        if let Some(old_index) = old_value {
            span_bug!(self.mir.source_info(start_location).span,
                      "found already pending activation for temp: {:?} \
                       at borrow_index: {:?} with associated data {:?}",
                      temp, old_index, self.idx_vec[old_index]);
        }
    }
}
<|endoftext|>


<commit_before>use rustc_errors::DiagnosticBuilder;
use rustc_span::Span;
use smallvec::smallvec;
use smallvec::SmallVec;

use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};

use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
pub use rustc_infer::traits::util::*;

///////////////////////////////////////////////////////////////////////////
// `TraitAliasExpander` iterator
///////////////////////////////////////////////////////////////////////////

/// "Trait alias expansion" is the process of expanding a sequence of trait
/// references into another sequence by transitively following all trait
/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias
/// `trait Foo = Bar + Sync;`, and another trait alias
/// `trait Bar = Read + Write`, then the bounds would expand to
/// `Read + Write + Sync + Send`.
/// Expansion is done via a DFS (depth-first search), and the `visited` field
/// is used to avoid cycles.
pub struct TraitAliasExpander<'tcx> {
    tcx: TyCtxt<'tcx>,
    stack: Vec<TraitAliasExpansionInfo<'tcx>>,
}

/// Stores information about the expansion of a trait via a path of zero or more trait aliases.
#[derive(Debug, Clone)]
pub struct TraitAliasExpansionInfo<'tcx> {
    pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>,
}

impl<'tcx> TraitAliasExpansionInfo<'tcx> {
    fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
        Self { path: smallvec![(trait_ref, span)] }
    }

    /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate
    /// trait aliases.
    pub fn label_with_exp_info(
        &self,
        diag: &mut DiagnosticBuilder<'_>,
        top_label: &str,
        use_desc: &str,
    ) {
        diag.span_label(self.top().1, top_label);
        if self.path.len() > 1 {
            for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) {
                diag.span_label(*sp, format!("referenced here ({})", use_desc));
            }
        }
        diag.span_label(
            self.bottom().1,
            format!("trait alias used in trait object type ({})", use_desc),
        );
    }

    pub fn trait_ref(&self) -> &ty::PolyTraitRef<'tcx> {
        &self.top().0
    }

    pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
        self.path.last().unwrap()
    }

    pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
        self.path.first().unwrap()
    }

    fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
        let mut path = self.path.clone();
        path.push((trait_ref, span));

        Self { path }
    }
}

pub fn expand_trait_aliases<'tcx>(
    tcx: TyCtxt<'tcx>,
    trait_refs: impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)>,
) -> TraitAliasExpander<'tcx> {
    let items: Vec<_> =
        trait_refs.map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)).collect();
    TraitAliasExpander { tcx, stack: items }
}

impl<'tcx> TraitAliasExpander<'tcx> {
    /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item`
    /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`.
    /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a
    /// trait alias.
    /// The return value indicates whether `item` should be yielded to the user.
    fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
        let tcx = self.tcx;
        let trait_ref = item.trait_ref();
        let pred = trait_ref.without_const().to_predicate();

        debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);

        // Don't recurse if this bound is not a trait alias.
        let is_alias = tcx.is_trait_alias(trait_ref.def_id());
        if !is_alias {
            return true;
        }

        // Don't recurse if this trait alias is already on the stack for the DFS search.
        let anon_pred = anonymize_predicate(tcx, &pred);
        if item.path.iter().rev().skip(1).any(|(tr, _)| {
            anonymize_predicate(tcx, &tr.without_const().to_predicate()) == anon_pred
        }) {
            return false;
        }

        // Get components of trait alias.
        let predicates = tcx.super_predicates_of(trait_ref.def_id());

        let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
            pred.subst_supertrait(tcx, &trait_ref)
                .to_opt_poly_trait_ref()
                .map(|trait_ref| item.clone_and_push(trait_ref, *span))
        });
        debug!("expand_trait_aliases: items={:?}", items.clone());

        self.stack.extend(items);

        false
    }
}

impl<'tcx> Iterator for TraitAliasExpander<'tcx> {
    type Item = TraitAliasExpansionInfo<'tcx>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.stack.len(), None)
    }

    fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> {
        while let Some(item) = self.stack.pop() {
            if self.expand(&item) {
                return Some(item);
            }
        }
        None
    }
}

///////////////////////////////////////////////////////////////////////////
// Iterator over def-IDs of supertraits
///////////////////////////////////////////////////////////////////////////

pub struct SupertraitDefIds<'tcx> {
    tcx: TyCtxt<'tcx>,
    stack: Vec<DefId>,
    visited: FxHashSet<DefId>,
}

pub fn supertrait_def_ids(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SupertraitDefIds<'_> {
    SupertraitDefIds {
        tcx,
        stack: vec![trait_def_id],
        visited: Some(trait_def_id).into_iter().collect(),
    }
}

impl Iterator for SupertraitDefIds<'tcx> {
    type Item = DefId;

    fn next(&mut self) -> Option<DefId> {
        let def_id = self.stack.pop()?;
        let predicates = self.tcx.super_predicates_of(def_id);
        let visited = &mut self.visited;
        self.stack.extend(
            predicates
                .predicates
                .iter()
                .filter_map(|(pred, _)| pred.to_opt_poly_trait_ref())
                .map(|trait_ref| trait_ref.def_id())
                .filter(|&super_def_id| visited.insert(super_def_id)),
        );
        Some(def_id)
    }
}

///////////////////////////////////////////////////////////////////////////
// Other
///////////////////////////////////////////////////////////////////////////

/// Instantiate all bound parameters of the impl with the given substs,
/// returning the resulting trait ref and all obligations that arise.
/// The obligations are closed under normalization.
pub fn impl_trait_ref_and_oblig<'a, 'tcx>(
    selcx: &mut SelectionContext<'a, 'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    impl_def_id: DefId,
    impl_substs: SubstsRef<'tcx>,
) -> (ty::TraitRef<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
    let impl_trait_ref = selcx.tcx().impl_trait_ref(impl_def_id).unwrap();
    let impl_trait_ref = impl_trait_ref.subst(selcx.tcx(), impl_substs);
    let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } =
        super::normalize(selcx, param_env, ObligationCause::dummy(), &impl_trait_ref);

    let predicates = selcx.tcx().predicates_of(impl_def_id);
    let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
    let Normalized { value: predicates, obligations: normalization_obligations2 } =
        super::normalize(selcx, param_env, ObligationCause::dummy(), &predicates);
    let impl_obligations =
        predicates_for_generics(ObligationCause::dummy(), 0, param_env, predicates);

    let impl_obligations = impl_obligations
        .chain(normalization_obligations1.into_iter())
        .chain(normalization_obligations2.into_iter());

    (impl_trait_ref, impl_obligations)
}

/// See [`super::obligations_for_generics`].
pub fn predicates_for_generics<'tcx>(
    cause: ObligationCause<'tcx>,
    recursion_depth: usize,
    param_env: ty::ParamEnv<'tcx>,
    generic_bounds: ty::InstantiatedPredicates<'tcx>,
) -> impl Iterator<Item = PredicateObligation<'tcx>> {
    debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds);

    generic_bounds.predicates.into_iter().map(move |predicate| Obligation {
        cause: cause.clone(),
        recursion_depth,
        param_env,
        predicate,
    })
}

pub fn predicate_for_trait_ref<'tcx>(
    cause: ObligationCause<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    trait_ref: ty::TraitRef<'tcx>,
    recursion_depth: usize,
) -> PredicateObligation<'tcx> {
    Obligation {
        cause,
        param_env,
        recursion_depth,
        predicate: trait_ref.without_const().to_predicate(),
    }
}

pub fn predicate_for_trait_def(
    tcx: TyCtxt<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    cause: ObligationCause<'tcx>,
    trait_def_id: DefId,
    recursion_depth: usize,
    self_ty: Ty<'tcx>,
    params: &[GenericArg<'tcx>],
) -> PredicateObligation<'tcx> {
    let trait_ref =
        ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) };
    predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth)
}

/// Casts a trait reference into a reference to one of its super
/// traits; returns `None` if `target_trait_def_id` is not a
/// supertrait.
pub fn upcast_choices(
    tcx: TyCtxt<'tcx>,
    source_trait_ref: ty::PolyTraitRef<'tcx>,
    target_trait_def_id: DefId,
) -> Vec<ty::PolyTraitRef<'tcx>> {
    if source_trait_ref.def_id() == target_trait_def_id {
        return vec![source_trait_ref]; // Shortcut the most common case.
    }

    supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
}

/// Given a trait `trait_ref`, returns the number of vtable entries
/// that come from `trait_ref`, excluding its supertraits. Used in
/// computing the vtable base for an upcast trait of a trait object.
pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
    let mut entries = 0;
    // Count number of methods and add them to the total offset.
    // Skip over associated types and constants.
    for trait_item in tcx.associated_items(trait_ref.def_id()).in_definition_order() {
        if trait_item.kind == ty::AssocKind::Fn {
            entries += 1;
        }
    }
    entries
}

/// Given an upcast trait object described by `object`, returns the
/// index of the method `method_def_id` (which should be part of
/// `object.upcast_trait_ref`) within the vtable for `object`.
pub fn get_vtable_index_of_object_method<N>(
    tcx: TyCtxt<'tcx>,
    object: &super::VtableObjectData<'tcx, N>,
    method_def_id: DefId,
) -> usize {
    // Count number of methods preceding the one we are selecting and
    // add them to the total offset.
    // Skip over associated types and constants.
    let mut entries = object.vtable_base;
    for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() {
        if trait_item.def_id == method_def_id {
            // The item with the ID we were given really ought to be a method.
            assert_eq!(trait_item.kind, ty::AssocKind::Fn);
            return entries;
        }
        if trait_item.kind == ty::AssocKind::Fn {
            entries += 1;
        }
    }

    bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
}

pub fn closure_trait_ref_and_return_type(
    tcx: TyCtxt<'tcx>,
    fn_trait_def_id: DefId,
    self_ty: Ty<'tcx>,
    sig: ty::PolyFnSig<'tcx>,
    tuple_arguments: TupleArgumentsFlag,
) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> {
    let arguments_tuple = match tuple_arguments {
        TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
        TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()),
    };
    let trait_ref = ty::TraitRef {
        def_id: fn_trait_def_id,
        substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]),
    };
    ty::Binder::bind((trait_ref, sig.skip_binder().output()))
}

pub fn generator_trait_ref_and_outputs(
    tcx: TyCtxt<'tcx>,
    fn_trait_def_id: DefId,
    self_ty: Ty<'tcx>,
    sig: ty::PolyGenSig<'tcx>,
) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
    let trait_ref = ty::TraitRef {
        def_id: fn_trait_def_id,
        substs: tcx.mk_substs_trait(self_ty, &[sig.skip_binder().resume_ty.into()]),
    };
    ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty))
}

pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
    assoc_item.defaultness.is_final() && tcx.impl_defaultness(assoc_item.container.id()).is_final()
}

pub enum TupleArgumentsFlag {
    Yes,
    No,
}
<commit_msg>Rollup merge of #71739 - tshepang:master, r=Dylan-DPC<commit_after>use rustc_errors::DiagnosticBuilder;
use rustc_span::Span;
use smallvec::smallvec;
use smallvec::SmallVec;

use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};

use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
pub use rustc_infer::traits::util::*;

///////////////////////////////////////////////////////////////////////////
// `TraitAliasExpander` iterator
///////////////////////////////////////////////////////////////////////////

/// "Trait alias expansion" is the process of expanding a sequence of trait
/// references into another sequence by transitively following all trait
/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias
/// `trait Foo = Bar + Sync;`, and another trait alias
/// `trait Bar = Read + Write`, then the bounds would expand to
/// `Read + Write + Sync + Send`.
/// Expansion is done via a DFS (depth-first search), and the `visited` field
/// is used to avoid cycles.
pub struct TraitAliasExpander<'tcx> {
    tcx: TyCtxt<'tcx>,
    stack: Vec<TraitAliasExpansionInfo<'tcx>>,
}

/// Stores information about the expansion of a trait via a path of zero or more trait aliases.
#[derive(Debug, Clone)]
pub struct TraitAliasExpansionInfo<'tcx> {
    pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>,
}

impl<'tcx> TraitAliasExpansionInfo<'tcx> {
    fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
        Self { path: smallvec![(trait_ref, span)] }
    }

    /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate
    /// trait aliases.
    pub fn label_with_exp_info(
        &self,
        diag: &mut DiagnosticBuilder<'_>,
        top_label: &str,
        use_desc: &str,
    ) {
        diag.span_label(self.top().1, top_label);
        if self.path.len() > 1 {
            for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) {
                diag.span_label(*sp, format!("referenced here ({})", use_desc));
            }
        }
        diag.span_label(
            self.bottom().1,
            format!("trait alias used in trait object type ({})", use_desc),
        );
    }

    pub fn trait_ref(&self) -> &ty::PolyTraitRef<'tcx> {
        &self.top().0
    }

    pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
        self.path.last().unwrap()
    }

    pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
        self.path.first().unwrap()
    }

    fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
        let mut path = self.path.clone();
        path.push((trait_ref, span));

        Self { path }
    }
}

pub fn expand_trait_aliases<'tcx>(
    tcx: TyCtxt<'tcx>,
    trait_refs: impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)>,
) -> TraitAliasExpander<'tcx> {
    let items: Vec<_> =
        trait_refs.map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)).collect();
    TraitAliasExpander { tcx, stack: items }
}

impl<'tcx> TraitAliasExpander<'tcx> {
    /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item`
    /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`.
    /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a
    /// trait alias.
    /// The return value indicates whether `item` should be yielded to the user.
    fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
        let tcx = self.tcx;
        let trait_ref = item.trait_ref();
        let pred = trait_ref.without_const().to_predicate();

        debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);

        // Don't recurse if this bound is not a trait alias.
        let is_alias = tcx.is_trait_alias(trait_ref.def_id());
        if !is_alias {
            return true;
        }

        // Don't recurse if this trait alias is already on the stack for the DFS search.
        let anon_pred = anonymize_predicate(tcx, &pred);
        if item.path.iter().rev().skip(1).any(|(tr, _)| {
            anonymize_predicate(tcx, &tr.without_const().to_predicate()) == anon_pred
        }) {
            return false;
        }

        // Get components of trait alias.
        let predicates = tcx.super_predicates_of(trait_ref.def_id());

        let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
            pred.subst_supertrait(tcx, &trait_ref)
                .to_opt_poly_trait_ref()
                .map(|trait_ref| item.clone_and_push(trait_ref, *span))
        });
        debug!("expand_trait_aliases: items={:?}", items.clone());

        self.stack.extend(items);

        false
    }
}

impl<'tcx> Iterator for TraitAliasExpander<'tcx> {
    type Item = TraitAliasExpansionInfo<'tcx>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.stack.len(), None)
    }

    fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> {
        while let Some(item) = self.stack.pop() {
            if self.expand(&item) {
                return Some(item);
            }
        }
        None
    }
}

///////////////////////////////////////////////////////////////////////////
// Iterator over def-IDs of supertraits
///////////////////////////////////////////////////////////////////////////

pub struct SupertraitDefIds<'tcx> {
    tcx: TyCtxt<'tcx>,
    stack: Vec<DefId>,
    visited: FxHashSet<DefId>,
}

pub fn supertrait_def_ids(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SupertraitDefIds<'_> {
    SupertraitDefIds {
        tcx,
        stack: vec![trait_def_id],
        visited: Some(trait_def_id).into_iter().collect(),
    }
}

impl Iterator for SupertraitDefIds<'tcx> {
    type Item = DefId;

    fn next(&mut self) -> Option<DefId> {
        let def_id = self.stack.pop()?;
        let predicates = self.tcx.super_predicates_of(def_id);
        let visited = &mut self.visited;
        self.stack.extend(
            predicates
                .predicates
                .iter()
                .filter_map(|(pred, _)| pred.to_opt_poly_trait_ref())
                .map(|trait_ref| trait_ref.def_id())
                .filter(|&super_def_id| visited.insert(super_def_id)),
        );
        Some(def_id)
    }
}

///////////////////////////////////////////////////////////////////////////
// Other
///////////////////////////////////////////////////////////////////////////

/// Instantiate all bound parameters of the impl with the given substs,
/// returning the resulting trait ref and all obligations that arise.
/// The obligations are closed under normalization.
pub fn impl_trait_ref_and_oblig<'a, 'tcx>(
    selcx: &mut SelectionContext<'a, 'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    impl_def_id: DefId,
    impl_substs: SubstsRef<'tcx>,
) -> (ty::TraitRef<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
    let impl_trait_ref = selcx.tcx().impl_trait_ref(impl_def_id).unwrap();
    let impl_trait_ref = impl_trait_ref.subst(selcx.tcx(), impl_substs);
    let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } =
        super::normalize(selcx, param_env, ObligationCause::dummy(), &impl_trait_ref);

    let predicates = selcx.tcx().predicates_of(impl_def_id);
    let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
    let Normalized { value: predicates, obligations: normalization_obligations2 } =
        super::normalize(selcx, param_env, ObligationCause::dummy(), &predicates);
    let impl_obligations =
        predicates_for_generics(ObligationCause::dummy(), 0, param_env, predicates);

    let impl_obligations = impl_obligations
        .chain(normalization_obligations1.into_iter())
        .chain(normalization_obligations2.into_iter());

    (impl_trait_ref, impl_obligations)
}

pub fn predicates_for_generics<'tcx>(
    cause: ObligationCause<'tcx>,
    recursion_depth: usize,
    param_env: ty::ParamEnv<'tcx>,
    generic_bounds: ty::InstantiatedPredicates<'tcx>,
) -> impl Iterator<Item = PredicateObligation<'tcx>> {
    debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds);

    generic_bounds.predicates.into_iter().map(move |predicate| Obligation {
        cause: cause.clone(),
        recursion_depth,
        param_env,
        predicate,
    })
}

pub fn predicate_for_trait_ref<'tcx>(
    cause: ObligationCause<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    trait_ref: ty::TraitRef<'tcx>,
    recursion_depth: usize,
) -> PredicateObligation<'tcx> {
    Obligation {
        cause,
        param_env,
        recursion_depth,
        predicate: trait_ref.without_const().to_predicate(),
    }
}

pub fn predicate_for_trait_def(
    tcx: TyCtxt<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    cause: ObligationCause<'tcx>,
    trait_def_id: DefId,
    recursion_depth: usize,
    self_ty: Ty<'tcx>,
    params: &[GenericArg<'tcx>],
) -> PredicateObligation<'tcx> {
    let trait_ref =
        ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) };
    predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth)
}

/// Casts a trait reference into a reference to one of its super
/// traits; returns `None` if `target_trait_def_id` is not a
/// supertrait.
pub fn upcast_choices(
    tcx: TyCtxt<'tcx>,
    source_trait_ref: ty::PolyTraitRef<'tcx>,
    target_trait_def_id: DefId,
) -> Vec<ty::PolyTraitRef<'tcx>> {
    if source_trait_ref.def_id() == target_trait_def_id {
        return vec![source_trait_ref]; // Shortcut the most common case.
    }

    supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
}

/// Given a trait `trait_ref`, returns the number of vtable entries
/// that come from `trait_ref`, excluding its supertraits. Used in
/// computing the vtable base for an upcast trait of a trait object.
pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
    let mut entries = 0;
    // Count number of methods and add them to the total offset.
    // Skip over associated types and constants.
    for trait_item in tcx.associated_items(trait_ref.def_id()).in_definition_order() {
        if trait_item.kind == ty::AssocKind::Fn {
            entries += 1;
        }
    }
    entries
}

/// Given an upcast trait object described by `object`, returns the
/// index of the method `method_def_id` (which should be part of
/// `object.upcast_trait_ref`) within the vtable for `object`.
pub fn get_vtable_index_of_object_method<N>(
    tcx: TyCtxt<'tcx>,
    object: &super::VtableObjectData<'tcx, N>,
    method_def_id: DefId,
) -> usize {
    // Count number of methods preceding the one we are selecting and
    // add them to the total offset.
    // Skip over associated types and constants.
    let mut entries = object.vtable_base;
    for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() {
        if trait_item.def_id == method_def_id {
            // The item with the ID we were given really ought to be a method.
            assert_eq!(trait_item.kind, ty::AssocKind::Fn);
            return entries;
        }
        if trait_item.kind == ty::AssocKind::Fn {
            entries += 1;
        }
    }

    bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
}

pub fn closure_trait_ref_and_return_type(
    tcx: TyCtxt<'tcx>,
    fn_trait_def_id: DefId,
    self_ty: Ty<'tcx>,
    sig: ty::PolyFnSig<'tcx>,
    tuple_arguments: TupleArgumentsFlag,
) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> {
    let arguments_tuple = match tuple_arguments {
        TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
        TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()),
    };
    let trait_ref = ty::TraitRef {
        def_id: fn_trait_def_id,
        substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]),
    };
    ty::Binder::bind((trait_ref, sig.skip_binder().output()))
}

pub fn generator_trait_ref_and_outputs(
    tcx: TyCtxt<'tcx>,
    fn_trait_def_id: DefId,
    self_ty: Ty<'tcx>,
    sig: ty::PolyGenSig<'tcx>,
) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
    let trait_ref = ty::TraitRef {
        def_id: fn_trait_def_id,
        substs: tcx.mk_substs_trait(self_ty, &[sig.skip_binder().resume_ty.into()]),
    };
    ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty))
}

pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
    assoc_item.defaultness.is_final() && tcx.impl_defaultness(assoc_item.container.id()).is_final()
}

pub enum TupleArgumentsFlag {
    Yes,
    No,
}
<|endoftext|>


<commit_before>extern crate telos;
use std::io::{Read, Write};
use telos::new_client;
use std::net::{TcpStream, TcpListener};
use std::thread;
use std::time::Duration;

#[test]
fn test_client() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut c = new_client()
        .ca_file("tests/cert.pem")
        .connect(tcp, "google.com").unwrap();
    c.handshake().unwrap();

    let notbefore = c.peer_cert_notbefore().unwrap();
    let notafter = c.peer_cert_notafter().unwrap();
    assert!(notbefore < notafter);
    assert!(c.peer_cert_provided());
    assert!(c.peer_cert_contains_name("google.com"));

    // Start an HTTP request just to check read/write
    c.write("GET / HTTP/1.1\n\n".as_bytes()).unwrap();
    let mut buf = [0u8; 256];
    c.read(&mut buf).unwrap();
    println!("{}", String::from_utf8_lossy(&buf));
    assert!(buf.starts_with(b"HTTP/1.1 "));
}

#[test]
fn stream_write_read() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect(tcp, "google.com")
                .unwrap();

    cli.write("GET / HTTP/1.1\n\n".as_bytes()).unwrap();
    let mut buf = [0u8; 256];
    cli.read(&mut buf).unwrap();
    assert!(buf.starts_with(b"HTTP/1.1 "));
}

#[test]
fn shutdown_twice_fails() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect(tcp, "www.google.com")
                .unwrap();

    cli.handshake().unwrap();
    cli.shutdown().unwrap();
    assert!(cli.shutdown().is_err());
}

#[test]
fn shutdown_without_handshake_fails() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect(tcp, "google.com")
                .unwrap();

    assert!(cli.shutdown().is_err());
}

#[test]
fn ca_invalid() {
    // This will fail because there is no CA file
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let cli = new_client()
                .ca_path(".")
                .ca_file("")
                .connect(tcp, "google.com");
    assert!(cli.is_err());
}

#[test]
fn ca_string() {
    let pem = include_str!("cert.pem");
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca(&pem)
                .connect(tcp, "google.com")
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn ca_string_invalid() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let cli = new_client()
                .ca("--INVALID PEM")
                .connect(tcp, "google.com");
    assert!(cli.is_err());
}

#[test]
fn connect_hostport() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect(tcp, "google.com")
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn connect_socket() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect(tcp, "google.com")
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn double_handshake_is_error() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect(tcp, "google.com")
                .unwrap();

    cli.handshake().unwrap();
    assert!(cli.handshake().is_err());
}

#[test]
fn verify_depth() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .verify_depth(0)
                .connect(tcp, "google.com")
                .unwrap();
    assert!(cli.handshake().is_err());
}

#[test]
fn error_ciphers() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let cli = new_client()
                .ca_file("tests/cert.pem")
                .ciphers("unknown_cipher")
                .connect(tcp, "google.com");
    assert!(cli.is_err());
}

#[test]
fn client_handshake_blocks() {
    let srv = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = srv.local_addr().unwrap();

    let cli = thread::spawn(move ||{
        let tcp_stream = TcpStream::connect(addr).unwrap();
        tcp_stream.set_read_timeout(Some(Duration::new(1,0))).unwrap();
        let mut tls_stream = telos::new_client()
                .insecure_noverifyname()
                .insecure_noverifycert()
                .connect(tcp_stream, "").unwrap();
        let res = tls_stream.handshake();
        assert!(res.is_err());
        assert!(res.unwrap_err().wants_more());
    });

    // Accept TCP connection
    let tcp_conn = srv.incoming().next().unwrap().unwrap();
    let _ = cli.join();
}

#[test]
fn invalid_file_descriptor() {
    // This fails, the socket is closed
    let mut client = {
        let tcp = TcpStream::connect("google.com:443").unwrap();
        let mut client = telos::new_client()
            .insecure_noverifycert()
            .connect_socket(&tcp, "google.com")
            .unwrap();
        client
    };
    assert!(client.handshake().is_err());

    let mut client = {
        let tcp = TcpStream::connect("google.com:443").unwrap();
        let mut client = telos::new_client()
            .insecure_noverifycert()
            .connect(tcp, "google.com")
            .unwrap();
        client
    };
    client.handshake().unwrap();
}

#[test]
fn inner_stream() {
        use std::net::Shutdown;

        let tcp = TcpStream::connect("google.com:443").unwrap();
        let mut client = telos::new_client()
            .insecure_noverifycert()
            .connect(tcp, "google.com")
            .unwrap();

        client.inner().shutdown(Shutdown::Both).unwrap();
        assert!(client.handshake().is_err());
}
<commit_msg>Test for default values before handshake<commit_after>extern crate telos;
use std::io::{Read, Write};
use telos::new_client;
use std::net::{TcpStream, TcpListener};
use std::thread;
use std::time::Duration;

#[test]
fn test_client() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut c = new_client()
        .ca_file("tests/cert.pem")
        .connect(tcp, "google.com").unwrap();

    // Defaults before the handshake
    assert!(c.certificate_issuer().is_empty());
    assert!(c.certificate_hash().is_empty());
    assert!(c.certificate_subject().is_empty());
    assert!(c.version().is_empty());
    assert!(c.cipher().is_empty());

    c.handshake().unwrap();

    let notbefore = c.peer_cert_notbefore().unwrap();
    let notafter = c.peer_cert_notafter().unwrap();
    assert!(notbefore < notafter);
    assert!(c.peer_cert_provided());
    assert!(c.peer_cert_contains_name("google.com"));

    // Start an HTTP request just to check read/write
    c.write("GET / HTTP/1.1\n\n".as_bytes()).unwrap();
    let mut buf = [0u8; 256];
    c.read(&mut buf).unwrap();
    println!("{}", String::from_utf8_lossy(&buf));
    assert!(buf.starts_with(b"HTTP/1.1 "));

    // After the handshake
    assert!(!c.certificate_issuer().is_empty());
    assert!(!c.certificate_hash().is_empty());
    assert!(!c.certificate_subject().is_empty());
    assert!(!c.version().is_empty());
    assert!(!c.cipher().is_empty());
}

#[test]
fn stream_write_read() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect(tcp, "google.com")
                .unwrap();

    cli.write("GET / HTTP/1.1\n\n".as_bytes()).unwrap();
    let mut buf = [0u8; 256];
    cli.read(&mut buf).unwrap();
    assert!(buf.starts_with(b"HTTP/1.1 "));
}

#[test]
fn shutdown_twice_fails() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect(tcp, "www.google.com")
                .unwrap();

    cli.handshake().unwrap();
    cli.shutdown().unwrap();
    assert!(cli.shutdown().is_err());
}

#[test]
fn shutdown_without_handshake_fails() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect(tcp, "google.com")
                .unwrap();

    assert!(cli.shutdown().is_err());
}

#[test]
fn ca_invalid() {
    // This will fail because there is no CA file
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let cli = new_client()
                .ca_path(".")
                .ca_file("")
                .connect(tcp, "google.com");
    assert!(cli.is_err());
}

#[test]
fn ca_string() {
    let pem = include_str!("cert.pem");
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca(&pem)
                .connect(tcp, "google.com")
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn ca_string_invalid() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let cli = new_client()
                .ca("--INVALID PEM")
                .connect(tcp, "google.com");
    assert!(cli.is_err());
}

#[test]
fn connect_hostport() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect(tcp, "google.com")
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn connect_socket() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect(tcp, "google.com")
                .unwrap();
    cli.handshake().unwrap();
}

#[test]
fn double_handshake_is_error() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .connect(tcp, "google.com")
                .unwrap();

    cli.handshake().unwrap();
    assert!(cli.handshake().is_err());
}

#[test]
fn verify_depth() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let mut cli = new_client()
                .ca_file("tests/cert.pem")
                .verify_depth(0)
                .connect(tcp, "google.com")
                .unwrap();
    assert!(cli.handshake().is_err());
}

#[test]
fn error_ciphers() {
    let tcp = TcpStream::connect("google.com:443").unwrap();
    let cli = new_client()
                .ca_file("tests/cert.pem")
                .ciphers("unknown_cipher")
                .connect(tcp, "google.com");
    assert!(cli.is_err());
}

#[test]
fn client_handshake_blocks() {
    let srv = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = srv.local_addr().unwrap();

    let cli = thread::spawn(move ||{
        let tcp_stream = TcpStream::connect(addr).unwrap();
        tcp_stream.set_read_timeout(Some(Duration::new(1,0))).unwrap();
        let mut tls_stream = telos::new_client()
                .insecure_noverifyname()
                .insecure_noverifycert()
                .connect(tcp_stream, "").unwrap();
        let res = tls_stream.handshake();
        assert!(res.is_err());
        assert!(res.unwrap_err().wants_more());
    });

    // Accept TCP connection
    let tcp_conn = srv.incoming().next().unwrap().unwrap();
    let _ = cli.join();
}

#[test]
fn invalid_file_descriptor() {
    // This fails, the socket is closed
    let mut client = {
        let tcp = TcpStream::connect("google.com:443").unwrap();
        let mut client = telos::new_client()
            .insecure_noverifycert()
            .connect_socket(&tcp, "google.com")
            .unwrap();
        client
    };
    assert!(client.handshake().is_err());

    let mut client = {
        let tcp = TcpStream::connect("google.com:443").unwrap();
        let mut client = telos::new_client()
            .insecure_noverifycert()
            .connect(tcp, "google.com")
            .unwrap();
        client
    };
    client.handshake().unwrap();
}

#[test]
fn inner_stream() {
        use std::net::Shutdown;

        let tcp = TcpStream::connect("google.com:443").unwrap();
        let mut client = telos::new_client()
            .insecure_noverifycert()
            .connect(tcp, "google.com")
            .unwrap();

        client.inner().shutdown(Shutdown::Both).unwrap();
        assert!(client.handshake().is_err());
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::ops::MulAssign;
use alga::linear::Transformation;
use na::{self, DVector, Dim, Dynamic, Real, U1, Unit, VectorSliceMutN};
use ncollide::query::ContactKinematic;

use object::{BodyHandle, BodySet};
use solver::helper;
use solver::{ForceDirection, NonlinearUnilateralConstraint};
use math::{Point, Vector};

pub struct NonlinearSORProx<N: Real> {
    _phantom: PhantomData<N>,
}

impl<N: Real> NonlinearSORProx<N> {
    pub fn new() -> Self {
        NonlinearSORProx {
            _phantom: PhantomData,
        }
    }

    pub fn solve(
        &self,
        bodies: &mut BodySet<N>,
        constraints: &mut [NonlinearUnilateralConstraint<N>],
        mj_lambda: &mut DVector<N>,
        jacobians: &mut [N],
        max_iter: usize,
    ) {
        for _ in 0..max_iter {
            for constraint in constraints.iter_mut() {
                // FIXME: specialize for SPATIAL_DIM.
                let dim1 = Dynamic::new(constraint.ndofs1);
                let dim2 = Dynamic::new(constraint.ndofs2);
                self.solve_unilateral(bodies, constraint, mj_lambda, jacobians, dim1, dim2)
            }
        }
    }

    fn solve_unilateral<D1: Dim, D2: Dim>(
        &self,
        bodies: &mut BodySet<N>,
        constraint: &mut NonlinearUnilateralConstraint<N>,
        mj_lambda: &mut DVector<N>,
        jacobians: &mut [N],
        dim1: D1,
        dim2: D2,
    ) {
        self.update_constraint(bodies, constraint, mj_lambda, jacobians);

        let impulse = na::sup(&N::zero(), &(-constraint.rhs / constraint.inv_r));

        VectorSliceMutN::new_generic_mut(jacobians, dim1, U1).mul_assign(impulse);
        VectorSliceMutN::new_generic_mut(&mut jacobians[dim1.value()..], dim2, U1)
            .mul_assign(impulse);

        bodies
            .body_mut(constraint.body1)
            .apply_displacement(&jacobians[0..dim1.value()]);
        bodies
            .body_mut(constraint.body2)
            .apply_displacement(&jacobians[dim1.value()..dim1.value() + dim2.value()]);
    }

    fn update_constraint(
        &self,
        bodies: &BodySet<N>,
        constraint: &mut NonlinearUnilateralConstraint<N>,
        mj_lambda: &mut DVector<N>,
        jacobians: &mut [N],
    ) {
        let body1 = bodies.body_part(constraint.body1);
        let body2 = bodies.body_part(constraint.body2);

        let m1 = body1.position();
        let m2 = body2.position();

        let mut world1 = m1.transform_point(&constraint.local1);
        let mut world2 = m2.transform_point(&constraint.local2);
        let normal;
        let depth;

        match constraint.kinematic {
            ContactKinematic::PlanePoint => {
                normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
                depth = na::dot(normal.as_ref(), &(world2 - world1));
                world1 = world2 - normal.as_ref() * depth;
            }
            ContactKinematic::PointPlane => {
                let normal2 = Unit::new_unchecked(m2.transform_vector(constraint.normal2.as_ref()));
                depth = na::dot(normal2.as_ref(), &(world1 - world2));
                world2 = world1 - normal2.as_ref() * depth;
            }
            ContactKinematic::PointPoint => {
                depth = na::distance(&world1, &world2);
            }
            ContactKinematic::LinePoint(dir1) => {
                let mut shift = world2 - world1;
                let proj = na::dot(dir1.as_ref(), &shift);
                shift -= dir1.as_ref() * proj;
                world1 = world2 - shift;
                depth = na::norm(&shift);
            }
            ContactKinematic::PointLine(dir2) => {
                let mut shift = world1 - world2;
                let proj = na::dot(dir2.as_ref(), &shift);
                shift -= dir2.as_ref() * proj;
                world2 = world1 - shift;
                depth = na::norm(&shift);
            }
            ContactKinematic::LineLine(dir1, dir2) => unimplemented!(),
            ContactKinematic::Unknown => {
                let a = N::zero();
                depth = N::zero();
            }
        }

        constraint.rhs = depth;

        helper::fill_constraint_geometry(
            &body1,
            constraint.ndofs1,
            &world1,
            &ForceDirection::Linear(normal1),
            constraint.ndofs1 + constraint.ndofs2,
            0,
            jacobians,
            &mut constraint.inv_r,
        );

        helper::fill_constraint_geometry(
            &body2,
            constraint.ndofs2,
            &world2,
            &ForceDirection::Linear(normal2),
            (constraint.ndofs1 * 2) + constraint.ndofs2,
            constraint.ndofs1,
            jacobians,
            &mut constraint.inv_r,
        );
    }
}
<commit_msg>Fix some contact update on the non-linear solver.<commit_after>use std::marker::PhantomData;
use std::ops::MulAssign;
use approx::ApproxEq;
use alga::linear::Transformation;
use na::{self, DVector, Dim, Dynamic, Real, U1, Unit, VectorSliceMutN};
use ncollide::query::ContactKinematic;

use object::{BodyHandle, BodySet};
use solver::helper;
use solver::{ForceDirection, NonlinearUnilateralConstraint};
use math::{Point, Vector};

pub struct NonlinearSORProx<N: Real> {
    _phantom: PhantomData<N>,
}

impl<N: Real> NonlinearSORProx<N> {
    pub fn new() -> Self {
        NonlinearSORProx {
            _phantom: PhantomData,
        }
    }

    pub fn solve(
        &self,
        bodies: &mut BodySet<N>,
        constraints: &mut [NonlinearUnilateralConstraint<N>],
        mj_lambda: &mut DVector<N>,
        jacobians: &mut [N],
        max_iter: usize,
    ) {
        for _ in 0..max_iter {
            for constraint in constraints.iter_mut() {
                // FIXME: specialize for SPATIAL_DIM.
                let dim1 = Dynamic::new(constraint.ndofs1);
                let dim2 = Dynamic::new(constraint.ndofs2);
                self.solve_unilateral(bodies, constraint, mj_lambda, jacobians, dim1, dim2)
            }
        }
    }

    fn solve_unilateral<D1: Dim, D2: Dim>(
        &self,
        bodies: &mut BodySet<N>,
        constraint: &mut NonlinearUnilateralConstraint<N>,
        mj_lambda: &mut DVector<N>,
        jacobians: &mut [N],
        dim1: D1,
        dim2: D2,
    ) {
        self.update_constraint(bodies, constraint, jacobians);

        let impulse = -constraint.rhs / constraint.inv_r;

        if impulse > N::zero() {
            VectorSliceMutN::new_generic_mut(jacobians, dim1, U1).mul_assign(impulse);
            VectorSliceMutN::new_generic_mut(&mut jacobians[dim1.value()..], dim2, U1)
                .mul_assign(impulse);

            bodies
                .body_mut(constraint.body1)
                .apply_displacement(&jacobians[0..dim1.value()]);
            bodies
                .body_mut(constraint.body2)
                .apply_displacement(&jacobians[dim1.value()..dim1.value() + dim2.value()]);
        }
    }

    fn update_constraint(
        &self,
        bodies: &BodySet<N>,
        constraint: &mut NonlinearUnilateralConstraint<N>,
        jacobians: &mut [N],
    ) {
        let body1 = bodies.body_part(constraint.body1);
        let body2 = bodies.body_part(constraint.body2);

        let m1 = body1.position();
        let m2 = body2.position();

        let mut world1 = m1.transform_point(&constraint.local1);
        let mut world2 = m2.transform_point(&constraint.local2);
        let normal;
        let depth;

        match constraint.kinematic {
            ContactKinematic::PlanePoint => {
                normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
                depth = -na::dot(normal.as_ref(), &(world2 - world1));
                world1 = world2 + normal.as_ref() * depth;
            }
            ContactKinematic::PointPlane => {
                let normal2 = m2.transform_vector(constraint.normal2.as_ref());
                depth = -na::dot(&normal2, &(world1 - world2));
                world2 = world1 + &normal2 * depth;
                normal = Unit::new_unchecked(-normal2);
            }
            ContactKinematic::PointPoint => {
                // if let Some((n, d)) = Unit::try_new_and_get(world2 - world1, N::default_epsilon()) {
                //     depth = -d;
                //     normal = n;
                // } else {
                depth = -constraint.margin1 - constraint.margin2;
                normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
                // }
            }
            ContactKinematic::LinePoint(dir1) => {
                let mut shift = world2 - world1;
                let proj = na::dot(dir1.as_ref(), &shift);
                shift -= dir1.as_ref() * proj;
                world1 = world2 - shift;

                if let Some((n, d)) = Unit::try_new_and_get(shift, N::zero()) {
                    depth = d;
                    normal = n;
                } else {
                    depth = na::zero();
                    normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
                }
            }
            ContactKinematic::PointLine(dir2) => {
                let mut shift = world1 - world2;
                let proj = na::dot(dir2.as_ref(), &shift);
                shift -= dir2.as_ref() * proj;
                world2 = world1 - shift;

                if let Some((n, d)) = Unit::try_new_and_get(shift, N::zero()) {
                    depth = d;
                    normal = n;
                } else {
                    depth = na::zero();
                    normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
                }
            }
            ContactKinematic::LineLine(dir1, dir2) => unimplemented!(),
            ContactKinematic::Unknown => {
                depth = N::zero();
                normal = Unit::new_unchecked(m1.transform_vector(constraint.normal1.as_ref()));
            }
        }

        let erp: N = na::convert(0.2); // XXX: don't hard-code this.s
        let allowed_error: N = na::convert(0.005); // XXX don't hard-code this.
        let max_correction: N = na::convert(0.2); // XXX don't hard-code this.
        constraint.rhs = na::sup(
            &((-(depth + constraint.margin1 + constraint.margin2)) * erp),
            &(-max_correction),
        );
        world1 += normal.unwrap() * constraint.margin1;
        world2 -= normal.unwrap() * constraint.margin2;

        helper::fill_constraint_geometry(
            &body1,
            constraint.ndofs1,
            &world1,
            &ForceDirection::Linear(-normal),
            constraint.ndofs1 + constraint.ndofs2,
            0,
            jacobians,
            &mut constraint.inv_r,
        );

        helper::fill_constraint_geometry(
            &body2,
            constraint.ndofs2,
            &world2,
            &ForceDirection::Linear(normal),
            (constraint.ndofs1 * 2) + constraint.ndofs2,
            constraint.ndofs1,
            jacobians,
            &mut constraint.inv_r,
        );

        // May happen sometimes for self-collisions (e.g. a multibody with itself).
        if constraint.inv_r.is_zero() {
            constraint.inv_r = N::one();
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;
use parser::ast::*;
use evaluator::types::*;

#[derive(Eq, Debug)]
pub enum Value {
    Int(i64),
    Bool(bool),
    String(String),
    Array(Vec<Value>),
    Hash(HashMap<Hashable, Value>),
    Fn {
        params: Vec<Ident>,
        body: BlockStmt,
        env: Box<Env>,
    },
    BuiltInFn {
        name: String,
        num_params: i32,
        func: BuiltInFn,
    },
    Return(Box<Value>),
    Null,
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Value::Int(i) => write!(f, "{}", i),
            &Value::Bool(b) => write!(f, "{}", b),
            &Value::String(ref s) => write!(f, "{}", s),
            &Value::Array(ref a) => unimplemented!(), // FIXME
            &Value::Hash(ref m) => unimplemented!(), // FIXME
            &Value::Fn { .. } => write!(f, "[function]"),
            &Value::BuiltInFn { ref name, .. } => write!(f, "[built-in function: {}", name),
            &Value::Return(ref o) => o.fmt(f),
            &Value::Null => write!(f, "null"),
        }
    }
}

impl PartialEq for Value {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (&Value::Int(i1), &Value::Int(i2)) => i1 == i2,
            (&Value::Bool(b1), &Value::Bool(b2)) => b1 == b2,
            (&Value::String(ref s1), &Value::String(ref s2)) => s1 == s2,
            (&Value::Array(ref v1), &Value::Array(ref v2)) => v1 == v2,
            (&Value::Hash(ref h1), &Value::Hash(ref h2)) => h1 == h2,
            (&Value::Fn {
                 params: ref p1,
                 body: ref b1,
                 env: ref e1,
             },
             &Value::Fn {
                 params: ref p2,
                 body: ref b2,
                 env: ref e2,
             }) => p1 == p2 && b1 == b2 && e1 == e2,
            (&Value::BuiltInFn {
                 name: ref n1,
                 num_params: ref p1,
                 ..
             },
             &Value::BuiltInFn {
                 name: ref n2,
                 num_params: ref p2,
                 ..
             }) => n1 == n2 && p1 == p2,
            (&Value::Return(ref o1), &Value::Return(ref o2)) => o1 == o2,
            (&Value::Null, &Value::Null) => true,
            _ => false,
        }
    }
}

#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Hashable {
    Int(i64),
    Bool(bool),
    String(String),
}

impl fmt::Display for Hashable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match self {
            &Hashable::Int(i) => Value::Int(i),
            &Hashable::Bool(b) => Value::Bool(b),
            &Hashable::String(ref s) => Value::String(s.clone()),
        })
    }
}

pub type BuiltInFn = fn(Vec<Value>) -> Result<Value>;
<commit_msg>Implement Display for array and hash value<commit_after>use std::collections::HashMap;
use std::fmt;
use common::util::unescape;
use parser::ast::*;
use evaluator::types::*;

#[derive(Eq, Debug)]
pub enum Value {
    Int(i64),
    Bool(bool),
    String(String),
    Array(Vec<Value>),
    Hash(HashMap<Hashable, Value>),
    Fn {
        params: Vec<Ident>,
        body: BlockStmt,
        env: Box<Env>,
    },
    BuiltInFn {
        name: String,
        num_params: i32,
        func: BuiltInFn,
    },
    Return(Box<Value>),
    Null,
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Value::Int(i) => write!(f, "{}", i),
            &Value::Bool(b) => write!(f, "{}", b),
            &Value::String(ref s) => write!(f, "{}", unescape(s)),
            &Value::Array(ref a) => {
                let mapped: Vec<String> = a.iter().map(|v| format!("{}", v)).collect();
                write!(f, "[{}]", mapped.join(", "))
            },
            &Value::Hash(ref m) => {
                let mut mapped: Vec<String> = m.iter().map(|(h, v)| format!("{}: {}", h, v)).collect();
                mapped.sort();
                write!(f, "{{{}}}", mapped.join(", "))
            },
            &Value::Fn { .. } => write!(f, "[function]"),
            &Value::BuiltInFn { ref name, .. } => write!(f, "[built-in function: {}]", name),
            &Value::Return(ref o) => o.fmt(f),
            &Value::Null => write!(f, "null"),
        }
    }
}

impl PartialEq for Value {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (&Value::Int(i1), &Value::Int(i2)) => i1 == i2,
            (&Value::Bool(b1), &Value::Bool(b2)) => b1 == b2,
            (&Value::String(ref s1), &Value::String(ref s2)) => s1 == s2,
            (&Value::Array(ref v1), &Value::Array(ref v2)) => v1 == v2,
            (&Value::Hash(ref h1), &Value::Hash(ref h2)) => h1 == h2,
            (&Value::Fn {
                 params: ref p1,
                 body: ref b1,
                 env: ref e1,
             },
             &Value::Fn {
                 params: ref p2,
                 body: ref b2,
                 env: ref e2,
             }) => p1 == p2 && b1 == b2 && e1 == e2,
            (&Value::BuiltInFn {
                 name: ref n1,
                 num_params: ref p1,
                 ..
             },
             &Value::BuiltInFn {
                 name: ref n2,
                 num_params: ref p2,
                 ..
             }) => n1 == n2 && p1 == p2,
            (&Value::Return(ref o1), &Value::Return(ref o2)) => o1 == o2,
            (&Value::Null, &Value::Null) => true,
            _ => false,
        }
    }
}

#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Hashable {
    Int(i64),
    Bool(bool),
    String(String),
}

impl fmt::Display for Hashable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match self {
            &Hashable::Int(i) => Value::Int(i),
            &Hashable::Bool(b) => Value::Bool(b),
            &Hashable::String(ref s) => Value::String(s.clone()),
        })
    }
}

pub type BuiltInFn = fn(Vec<Value>) -> Result<Value>;

#[cfg(test)]
mod tests {
    use super::*;
    use std::iter::FromIterator;

    fn dummy(_: Vec<Value>) -> Result<Value> {
        unreachable!()
    }

    #[test]
    fn value_display() {
        assert_eq!(format!("{}", Value::Int(35)), "35");
        assert_eq!(format!("{}", Value::Bool(true)), "true");
        assert_eq!(format!("{}", Value::String(String::from("hello\nworld"))),
                   "\"hello\\nworld\"");
        assert_eq!(format!("{}", Value::Array(vec![])), "[]");
        assert_eq!(format!("{}",
                           Value::Array(vec![Value::Int(1), Value::Int(2), Value::Int(3)])),
                   "[1, 2, 3]");
        assert_eq!(format!("{}", Value::Hash(HashMap::new())), "{}");
        assert_eq!(format!("{}",
                           Value::Hash(HashMap::from_iter(vec![(Hashable::Int(1),
                                                                Value::String(String::from("one"))),
                                                               (Hashable::Int(2),
                                                                Value::String(String::from("two"))),
                                                               (Hashable::Int(3),
                                                                Value::String(String::from("three")))]
                           ))),
                   "{1: \"one\", 2: \"two\", 3: \"three\"}");
        assert_eq!(format!("{}",
                           Value::Fn {
                               params: vec![],
                               body: vec![],
                               env: Box::new(Env::new()),
                           }),
                   "[function]");
        assert_eq!(format!("{}",
                           Value::BuiltInFn {
                               name: String::from("hi"),
                               num_params: 0,
                               func: dummy,
                           }),
                   "[built-in function: hi]");
        assert_eq!(format!("{}", Value::Return(Box::new(Value::Int(35)))), "35");
        assert_eq!(format!("{}", Value::Null), "null");
    }
}
<|endoftext|>


<commit_before>include!(concat!(env!("OUT_DIR"), "/protocol.rs"));

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_description() {
        assert_eq!(format!("{} - {}.{}.{}", metadata::NAME, metadata::MAJOR_VERSION, metadata::MINOR_VERSION, metadata::REVISION), "AMQP - 0.9.1");
    }
}
<commit_msg>protocol: add a BasicProperties alias to basic::AMQPProperties<commit_after>include!(concat!(env!("OUT_DIR"), "/protocol.rs"));

pub type BasicProperties = basic::AMQPProperties;

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_description() {
        assert_eq!(format!("{} - {}.{}.{}", metadata::NAME, metadata::MAJOR_VERSION, metadata::MINOR_VERSION, metadata::REVISION), "AMQP - 0.9.1");
    }
}
<|endoftext|>


<commit_before>#![feature(slice_patterns)]
extern crate eve;
extern crate hyper;
extern crate cookie;
extern crate mime;
extern crate url;
extern crate websocket;
extern crate rustc_serialize;

use std::io::Read;
use std::error::Error;
use hyper::net::Fresh;
use hyper::server::{Server, Request, Response};
use hyper::uri::RequestUri;
use hyper::Url;
use hyper::header::{Headers,ContentType,Location,SetCookie};
use cookie::Cookie;
use mime::Mime;
use url::SchemeData::Relative;
use rustc_serialize::json;
use websocket::{Message, Sender};

use eve::client::*;
use eve::server;
use eve::value::Value;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Session {
	client: String,
	id: String,
	user_id: String,
	object: String,
	created_at: f64,
	expires_at: f64,
	ip: String,
	user: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct User {
	custom: Custom,
	id: String,
	realm_id: String,
	username: String,
	state: String,
	user_type: String,
	reference: Option<String>,
	name: String,
	email: String,
	object: String,
	last_login_at: f64,
	last_login_on: f64,
	created_at: f64,
	first_name: Option<String>,
	last_name: Option<String>,
	credentials: Vec<Credential>,
	membership_count: f64,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Custom;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Credential {
	id: String,
	credential_type: String,
	object: String,
}

fn main() {
	Server::http(login).listen("0.0.0.0:8080").unwrap();
}

fn login(req: Request, mut res: Response<Fresh>) {

	match (&req.method.clone(), &req.uri.clone()) {
		(&hyper::Get, &RequestUri::AbsolutePath(ref relative_path)) => {

			// Form a url from the path
			let absolute_path = "http://localhost".to_string() + relative_path;
			let url = Url::parse(&*absolute_path).unwrap();

			// Get the file name
			let scheme_data = &url.scheme_data;

			let requested_file = match scheme_data {
				&Relative(ref rsd) => rsd.path[0].clone(),
				_ => panic!("Expected relative path"),
			};

			// Parse the query string
			let query_pairs = &url.query_pairs();

			// Handle login
			match &*requested_file {
				"login.html" => {
					println!("Authenticating User");
					let pairs = query_pairs.clone().unwrap();
					match &pairs[..] {
						[(ref token_type, ref token)] if token_type.clone() == "token".to_string() => {

							// We have a login token, now to authenticate
							let mut client = hyper::client::Client::new();
							let api_call = "https://api-e1.authrocket.com/v1/sessions/".to_string() + token;
							let req = client.request(hyper::method::Method::Get,&*api_call);

							// Set the appropriate headers for authorocket
							let mut headers = Headers::new();
							let json: Mime = "application/json".parse().unwrap();
							let content_type = ContentType(json);
							headers.set_raw("X-Authrocket-Account",vec!["org_0vC7wPw9XphPGQnSqYB6bz".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Api-Key",vec!["key_jtnCRWxQvDD0p5HATR9RBIe4WnxnwV6pWNzwmZQLnSZ".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Realm",vec!["rl_0vC7wd03CqwhpK7kT8fvAc".to_string().into_bytes()]);
							headers.set_raw("Accept",vec!["application/json".to_string().into_bytes()]);
							headers.set(content_type);

							// Send the request and receive a response with session data
							let mut client_res = req.headers(headers).send().unwrap();

							match client_res.status_raw() {

								&hyper::http::RawStatus(200,_) => {

									let mut body = String::new();
									client_res.read_to_string(&mut body).unwrap();
									let session_data: Session = json::decode(&body).unwrap();
									println!("Welcome to Eve, {:?}!",session_data.user.username);
									println!("Login Successful. Redirecting to user area.");

									// Connect to the Eve runtime and add the user to the eveusers table
									let ws_result = open_websocket("ws://192.168.137.38:2794");
									match ws_result {
										// If things went okay, redirect to the Eve UI
										Ok(mut sender) => {
											// Form the response
											*res.status_mut() = hyper::status::StatusCode::PermanentRedirect;

											// Form the response headers
											let mut headers = Headers::new();
											let location = Location("http://192.168.137.38:1234/editor.html".to_string());
											let user_cookie = Cookie::new("userid".to_string(),session_data.user.id.clone());
											let cookies = SetCookie(vec![user_cookie]);
											headers.set(location);
											headers.set(cookies);
											*res.headers_mut() = headers;

											// Create eveusers table and insert the new user
											let table_name = "eveusers";
											let table_fields = vec!["id","username"];
											let row_data = vec![
																Value::String(session_data.user.id.clone()),
																Value::String(session_data.user.username.clone())
														   	   ];
											let mut create_eveusers_table = create_table(&table_name,&table_fields,None);
											create_eveusers_table = insert_fact(&"tag",&vec!["view","tag"],&vec![Value::String("eveusers".to_string()),Value::String("remote".to_string())],Some(create_eveusers_table));
											let insert_user = insert_fact(&table_name,&table_fields,&row_data,None);
											send_event(&create_eveusers_table,&mut sender);
											send_event(&insert_user,&mut sender);
											let _ = sender.send_message(Message::Close(None));
										}
										// Otherwise, throw an error... maybe redirect to a special page.
										Err(e) => {
											println!("ERROR: Had trouble connecting to the Eve runtime: {}",e);
											*res.status_mut() = hyper::status::StatusCode::NotFound;
											panic!("Oh no!");
											//serve_file("404.html",res);
										}
									}

									println!("Login complete.");
								}
								_ => {
									println!("ERROR: Could not authenticate user with token {}",token);
									*res.status_mut() = hyper::status::StatusCode::Forbidden;
									panic!("Oh no!");
									//serve_file("404.html",res);
								}
							};
						},
						_ => panic!("Oh no!"), //serve_file("404.html",res),
					}
				},
				"logout.html" => {
					println!("Logging out...");
					let user_id = server::get_user_id(req.headers.get::<hyper::header::Cookie>());
                	println!("{:?}",user_id);
				},
				"favicon.ico" => (),
				other => panic!("Cannot serve {}",other), //serve_file(&*requested_file,res),
			};
		}
		_ => panic!("Oh no!"),
	}
}<commit_msg>Small change for handling login after sign up<commit_after>#![feature(slice_patterns)]
extern crate eve;
extern crate hyper;
extern crate cookie;
extern crate mime;
extern crate url;
extern crate websocket;
extern crate rustc_serialize;

use std::io::Read;
use std::error::Error;
use hyper::net::Fresh;
use hyper::server::{Server, Request, Response};
use hyper::uri::RequestUri;
use hyper::Url;
use hyper::header::{Headers,ContentType,Location,SetCookie};
use cookie::Cookie;
use mime::Mime;
use url::SchemeData::Relative;
use rustc_serialize::json;
use websocket::{Message, Sender};

use eve::client::*;
use eve::server;
use eve::value::Value;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Session {
	client: String,
	id: String,
	user_id: String,
	object: String,
	created_at: f64,
	expires_at: f64,
	ip: String,
	user: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct User {
	custom: Custom,
	id: String,
	realm_id: String,
	username: String,
	state: String,
	user_type: String,
	reference: Option<String>,
	name: String,
	email: String,
	object: String,
	last_login_at: f64,
	last_login_on: f64,
	created_at: f64,
	first_name: Option<String>,
	last_name: Option<String>,
	credentials: Vec<Credential>,
	membership_count: f64,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Custom;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Credential {
	id: String,
	credential_type: String,
	object: String,
}

fn main() {
	Server::http(login).listen("0.0.0.0:8080").unwrap();
}

fn login(req: Request, mut res: Response<Fresh>) {

	match (&req.method.clone(), &req.uri.clone()) {
		(&hyper::Get, &RequestUri::AbsolutePath(ref relative_path)) => {

			// Form a url from the path
			let absolute_path = "http://localhost".to_string() + relative_path;
			let url = Url::parse(&*absolute_path).unwrap();

			// Get the file name
			let scheme_data = &url.scheme_data;

			let requested_file = match scheme_data {
				&Relative(ref rsd) => rsd.path[0].clone(),
				_ => panic!("Expected relative path"),
			};

			// Parse the query string
			let query_pairs = &url.query_pairs();

			// Handle login
			match &*requested_file {
				"login.html" => {
					println!("Authenticating User");
					let pairs = query_pairs.clone().unwrap();
					match &pairs[..] {
						[(ref token_type, ref token), ..] if token_type.clone() == "token".to_string() => {

							// We have a login token, now to authenticate
							let mut client = hyper::client::Client::new();
							let api_call = "https://api-e1.authrocket.com/v1/sessions/".to_string() + token;
							let req = client.request(hyper::method::Method::Get,&*api_call);

							// Set the appropriate headers for authorocket
							let mut headers = Headers::new();
							let json: Mime = "application/json".parse().unwrap();
							let content_type = ContentType(json);
							headers.set_raw("X-Authrocket-Account",vec!["org_0vC7wPw9XphPGQnSqYB6bz".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Api-Key",vec!["key_jtnCRWxQvDD0p5HATR9RBIe4WnxnwV6pWNzwmZQLnSZ".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Realm",vec!["rl_0vC7wd03CqwhpK7kT8fvAc".to_string().into_bytes()]);
							headers.set_raw("Accept",vec!["application/json".to_string().into_bytes()]);
							headers.set(content_type);

							// Send the request and receive a response with session data
							let mut client_res = req.headers(headers).send().unwrap();

							match client_res.status_raw() {

								&hyper::http::RawStatus(200,_) => {

									let mut body = String::new();
									client_res.read_to_string(&mut body).unwrap();
									let session_data: Session = json::decode(&body).unwrap();
									println!("Welcome to Eve, {:?}!",session_data.user.username);
									println!("Login Successful. Redirecting to user area.");

									// Connect to the Eve runtime and add the user to the eveusers table
									let ws_result = open_websocket("ws://192.168.137.38:2794");
									match ws_result {
										// If things went okay, redirect to the Eve UI
										Ok(mut sender) => {
											// Form the response
											*res.status_mut() = hyper::status::StatusCode::PermanentRedirect;

											// Form the response headers
											let mut headers = Headers::new();
											let location = Location("http://192.168.137.38:1234/editor.html".to_string());
											let user_cookie = Cookie::new("userid".to_string(),session_data.user.id.clone());
											let cookies = SetCookie(vec![user_cookie]);
											headers.set(location);
											headers.set(cookies);
											*res.headers_mut() = headers;

											// Create eveusers table and insert the new user
											let table_name = "eveusers";
											let table_fields = vec!["id","username"];
											let row_data = vec![
																Value::String(session_data.user.id.clone()),
																Value::String(session_data.user.username.clone())
														   	   ];
											let mut create_eveusers_table = create_table(&table_name,&table_fields,None);
											create_eveusers_table = insert_fact(&"tag",&vec!["view","tag"],&vec![Value::String("eveusers".to_string()),Value::String("remote".to_string())],Some(create_eveusers_table));
											let insert_user = insert_fact(&table_name,&table_fields,&row_data,None);
											send_event(&create_eveusers_table,&mut sender);
											send_event(&insert_user,&mut sender);
											let _ = sender.send_message(Message::Close(None));
										}
										// Otherwise, throw an error... maybe redirect to a special page.
										Err(e) => {
											println!("ERROR: Had trouble connecting to the Eve runtime: {}. Is the server running?",e);
											*res.status_mut() = hyper::status::StatusCode::NotFound;
											panic!("Oh no!");
											//serve_file("404.html",res);
										}
									}

									println!("Login complete.");
								}
								_ => {
									println!("ERROR: Could not authenticate user with token {}",token);
									*res.status_mut() = hyper::status::StatusCode::Forbidden;
									panic!("Oh no!");
									//serve_file("404.html",res);
								}
							};
						},
						_ => panic!("Oh no!"), //serve_file("404.html",res),
					}
				},
				"logout.html" => {
					println!("Logging out...");
					let user_id = server::get_user_id(req.headers.get::<hyper::header::Cookie>());
                	println!("{:?}",user_id);
				},
				"favicon.ico" => (),
				other => panic!("Cannot serve {}",other), //serve_file(&*requested_file,res),
			};
		}
		_ => panic!("Oh no!"),
	}
}<|endoftext|>