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

use borrow_check::nll::region_infer::values::ToElementIndex;
use borrow_check::nll::region_infer::{Cause, ConstraintIndex, RegionInferenceContext};
use borrow_check::nll::region_infer::{ConstraintIndex, RegionInferenceContext};
use borrow_check::nll::type_check::Locations;
use rustc::hir::def_id::DefId;
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc::infer::InferCtxt;
use rustc::mir::{self, Location, Mir, Place, Rvalue, StatementKind, TerminatorKind};
use rustc::ty::RegionVid;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::IndexVec;
use std::fmt;
use syntax_pos::Span;

/// Constraints that are considered interesting can be categorized to
/// determine why they are interesting. Order of variants indicates
/// sort order of the category, thereby influencing diagnostic output.
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
enum ConstraintCategory {
    Cast,
    Assignment,
    Return,
    CallArgument,
    Other,
    Boring,
}

impl fmt::Display for ConstraintCategory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ConstraintCategory::Assignment => write!(f, "assignment"),
            ConstraintCategory::Return => write!(f, "return"),
            ConstraintCategory::Cast => write!(f, "cast"),
            ConstraintCategory::CallArgument => write!(f, "argument"),
            _ => write!(f, "free region"),
        }
    }
}

impl<'tcx> RegionInferenceContext<'tcx> {
    /// When reporting an error, it is useful to be able to determine which constraints influenced
    /// the region being reported as an error. This function finds all of the paths from the
    /// constraint.
    fn find_constraint_paths_from_region(&self, r0: RegionVid) -> Vec<Vec<ConstraintIndex>> {
        let constraints = self.constraints.clone();

        // Mapping of regions to the previous region and constraint index that led to it.
        let mut previous = FxHashMap();
        // Regions yet to be visited.
        let mut next = vec![r0];
        // Regions that have been visited.
        let mut visited = FxHashSet();
        // Ends of paths.
        let mut end_regions = FxHashSet();

        // When we've still got points to visit...
        while let Some(current) = next.pop() {
            // ...take the next point...
            debug!(
                "find_constraint_paths_from_region: current={:?} visited={:?} next={:?}",
                current, visited, next
            );
            // ...but make sure not to visit this point again...
            visited.insert(current);

            // ...find the edges containing it...
            let mut upcoming = Vec::new();
            for (index, constraint) in constraints.iter_enumerated() {
                if constraint.sub == current {
                    // ...add the regions that join us with to the path we've taken...
                    debug!(
                        "find_constraint_paths_from_region: index={:?} constraint={:?}",
                        index, constraint
                    );
                    let next_region = constraint.sup.clone();

                    // ...unless we've visited it since this was added...
                    if visited.contains(&next_region) {
                        debug!("find_constraint_paths_from_region: skipping as visited");
                        continue;
                    }

                    previous.insert(next_region, (index, Some(current)));
                    upcoming.push(next_region);
                }
            }

            if upcoming.is_empty() {
                // If we didn't find any edges then this is the end of a path...
                debug!(
                    "find_constraint_paths_from_region: new end region current={:?}",
                    current
                );
                end_regions.insert(current);
            } else {
                // ...but, if we did find edges, then add these to the regions yet to visit.
                debug!(
                    "find_constraint_paths_from_region: extend next upcoming={:?}",
                    upcoming
                );
                next.extend(upcoming);
            }
        }

        // Now we've visited each point, compute the final paths.
        let mut paths: Vec<Vec<ConstraintIndex>> = Vec::new();
        debug!(
            "find_constraint_paths_from_region: end_regions={:?}",
            end_regions
        );
        for end_region in end_regions {
            debug!(
                "find_constraint_paths_from_region: end_region={:?}",
                end_region
            );

            // Get the constraint and region that led to this end point.
            // We can unwrap as we know if end_point was in the vector that it
            // must also be in our previous map.
            let (mut index, mut region) = previous.get(&end_region).unwrap();
            debug!(
                "find_constraint_paths_from_region: index={:?} region={:?}",
                index, region
            );

            // Keep track of the indices.
            let mut path: Vec<ConstraintIndex> = vec![index];

            while region.is_some() && region != Some(r0) {
                let p = previous.get(&region.unwrap()).unwrap();
                index = p.0;
                region = p.1;

                debug!(
                    "find_constraint_paths_from_region: index={:?} region={:?}",
                    index, region
                );
                path.push(index);
            }

            // Add to our paths.
            paths.push(path);
        }

        debug!("find_constraint_paths_from_region: paths={:?}", paths);
        paths
    }

    /// This function will return true if a constraint is interesting and false if a constraint
    /// is not. It is useful in filtering constraint paths to only interesting points.
    fn constraint_is_interesting(&self, index: &ConstraintIndex) -> bool {
        self.constraints
            .get(*index)
            .filter(|constraint| {
                debug!(
                    "constraint_is_interesting: locations={:?} constraint={:?}",
                    constraint.locations, constraint
                );
                if let Locations::Interesting(_) = constraint.locations {
                    true
                } else {
                    false
                }
            })
            .is_some()
    }

    /// This function classifies a constraint from a location.
    fn classify_constraint(
        &self,
        index: &ConstraintIndex,
        mir: &Mir<'tcx>,
    ) -> Option<(ConstraintCategory, Span)> {
        let constraint = self.constraints.get(*index)?;
        let span = constraint.locations.span(mir);
        let location = constraint.locations.from_location()?;

        if !self.constraint_is_interesting(index) {
            return Some((ConstraintCategory::Boring, span));
        }

        let data = &mir[location.block];
        let category = if location.statement_index == data.statements.len() {
            if let Some(ref terminator) = data.terminator {
                match terminator.kind {
                    TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment,
                    TerminatorKind::Call { .. } => ConstraintCategory::CallArgument,
                    _ => ConstraintCategory::Other,
                }
            } else {
                ConstraintCategory::Other
            }
        } else {
            let statement = &data.statements[location.statement_index];
            match statement.kind {
                StatementKind::Assign(ref place, ref rvalue) => {
                    if *place == Place::Local(mir::RETURN_PLACE) {
                        ConstraintCategory::Return
                    } else {
                        match rvalue {
                            Rvalue::Cast(..) => ConstraintCategory::Cast,
                            Rvalue::Use(..) => ConstraintCategory::Assignment,
                            _ => ConstraintCategory::Other,
                        }
                    }
                }
                _ => ConstraintCategory::Other,
            }
        };

        Some((category, span))
    }

    /// Report an error because the universal region `fr` was required to outlive
    /// `outlived_fr` but it is not known to do so. For example:
    ///
    /// ```
    /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
    /// ```
    ///
    /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
    pub(super) fn report_error(
        &self,
        mir: &Mir<'tcx>,
        infcx: &InferCtxt<'_, '_, 'tcx>,
        mir_def_id: DefId,
        fr: RegionVid,
        outlived_fr: RegionVid,
        blame_span: Span,
    ) {
        // Obviously uncool error reporting.

        let fr_name = self.to_error_region(fr);
        let outlived_fr_name = self.to_error_region(outlived_fr);

        if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) {
            let tables = infcx.tcx.typeck_tables_of(mir_def_id);
            let nice = NiceRegionError::new_from_span(infcx.tcx, blame_span, o, f, Some(tables));
            if let Some(_error_reported) = nice.try_report() {
                return;
            }
        }

        let fr_string = match fr_name {
            Some(r) => format!("free region `{}`", r),
            None => format!("free region `{:?}`", fr),
        };

        let outlived_fr_string = match outlived_fr_name {
            Some(r) => format!("free region `{}`", r),
            None => format!("free region `{:?}`", outlived_fr),
        };

        let constraints = self.find_constraint_paths_from_region(fr.clone());
        let path = constraints.iter().min_by_key(|p| p.len()).unwrap();
        debug!("report_error: shortest_path={:?}", path);

        let mut categorized_path = path.iter()
            .filter_map(|index| self.classify_constraint(index, mir))
            .collect::<Vec<(ConstraintCategory, Span)>>();
        debug!("report_error: categorized_path={:?}", categorized_path);

        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
        debug!("report_error: sorted_path={:?}", categorized_path);

        if let Some((category, span)) = &categorized_path.first() {
            let mut diag = infcx.tcx.sess.struct_span_err(
                *span,
                &format!(
                    "{} requires that data must outlive {}",
                    category, outlived_fr_string
                ),
            );

            diag.emit();
        } else {
            let mut diag = infcx.tcx.sess.struct_span_err(
                blame_span,
                &format!("{} does not outlive {}", fr_string, outlived_fr_string,),
            );

            diag.emit();
        }
    }

    // Find some constraint `X: Y` where:
    // - `fr1: X` transitively
    // - and `Y` is live at `elem`
    crate fn find_constraint(&self, fr1: RegionVid, elem: Location) -> RegionVid {
        let index = self.blame_constraint(fr1, elem);
        self.constraints[index].sub
    }

    /// Tries to finds a good span to blame for the fact that `fr1`
    /// contains `fr2`.
    pub(super) fn blame_constraint(
        &self,
        fr1: RegionVid,
        elem: impl ToElementIndex,
    ) -> ConstraintIndex {
        // Find everything that influenced final value of `fr`.
        let influenced_fr1 = self.dependencies(fr1);

        // Try to find some outlives constraint `'X: fr2` where `'X`
        // influenced `fr1`. Blame that.
        //
        // NB, this is a pretty bad choice most of the time. In
        // particular, the connection between `'X` and `fr1` may not
        // be obvious to the user -- not to mention the naive notion
        // of dependencies, which doesn't account for the locations of
        // contraints at all. But it will do for now.
        let relevant_constraint = self.constraints
            .iter_enumerated()
            .filter_map(|(i, constraint)| {
                if !self.liveness_constraints.contains(constraint.sub, elem) {
                    None
                } else {
                    influenced_fr1[constraint.sup]
                        .map(|distance| (distance, i))
                }
            })
            .min() // constraining fr1 with fewer hops *ought* to be more obvious
            .map(|(_dist, i)| i);

        relevant_constraint.unwrap_or_else(|| {
            bug!(
                "could not find any constraint to blame for {:?}: {:?}",
                fr1,
                elem,
            );
        })
    }

    /// Finds all regions whose values `'a` may depend on in some way.
    /// For each region, returns either `None` (does not influence
    /// `'a`) or `Some(d)` which indicates that it influences `'a`
    /// with distinct `d` (minimum number of edges that must be
    /// traversed).
    ///
    /// Used during error reporting, extremely naive and inefficient.
    fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> {
        let mut result_set = IndexVec::from_elem(None, &self.definitions);
        let mut changed = true;
        result_set[r0] = Some(0); // distance 0 from `r0`

        while changed {
            changed = false;
            for constraint in &*self.constraints {
                if let Some(n) = result_set[constraint.sup] {
                    let m = n + 1;
                    if result_set[constraint.sub]
                        .map(|distance| m < distance)
                        .unwrap_or(true)
                    {
                        result_set[constraint.sub] = Some(m);
                        changed = true;
                    }
                }
            }
        }

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

use borrow_check::nll::region_infer::values::ToElementIndex;
use borrow_check::nll::region_infer::{Cause, ConstraintIndex, RegionInferenceContext};
use borrow_check::nll::region_infer::{ConstraintIndex, RegionInferenceContext};
use borrow_check::nll::type_check::Locations;
use rustc::hir::def_id::DefId;
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc::infer::InferCtxt;
use rustc::mir::{self, Location, Mir, Place, Rvalue, StatementKind, TerminatorKind};
use rustc::ty::RegionVid;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::IndexVec;
use std::fmt;
use syntax_pos::Span;

/// Constraints that are considered interesting can be categorized to
/// determine why they are interesting. Order of variants indicates
/// sort order of the category, thereby influencing diagnostic output.
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
enum ConstraintCategory {
    Cast,
    Assignment,
    Return,
    CallArgument,
    Other,
    Boring,
}

impl fmt::Display for ConstraintCategory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ConstraintCategory::Assignment => write!(f, "assignment"),
            ConstraintCategory::Return => write!(f, "return"),
            ConstraintCategory::Cast => write!(f, "cast"),
            ConstraintCategory::CallArgument => write!(f, "argument"),
            _ => write!(f, "free region"),
        }
    }
}

impl<'tcx> RegionInferenceContext<'tcx> {
    /// Walks the graph of constraints (where `'a: 'b` is considered
    /// an edge `'b -> 'a`) to find all paths from `from_region` to
    /// `to_region`. The paths are accumulated into the vector
    /// `results`. The paths are stored as a series of
    /// `ConstraintIndex` values -- in other words, a list of *edges*.
    ///
    /// # Parameters
    ///
    /// - `from_region`
    /// When reporting an error, it is useful to be able to determine
    /// which constraints influenced the region being reported as an
    /// error. This function finds all of the paths from the
    /// constraint.
    fn find_constraint_paths_between_regions(
        &self,
        from_region: RegionVid,
        to_region: RegionVid,
    ) -> Vec<Vec<ConstraintIndex>> {
        let mut results = vec![];
        self.find_constraint_paths_between_regions_helper(
            from_region,
            from_region,
            to_region,
            &mut FxHashSet::default(),
            &mut vec![],
            &mut results,
        );
        results
    }

    /// Helper for `find_constraint_paths_between_regions`.
    fn find_constraint_paths_between_regions_helper(
        &self,
        from_region: RegionVid,
        current_region: RegionVid,
        to_region: RegionVid,
        visited: &mut FxHashSet<RegionVid>,
        stack: &mut Vec<ConstraintIndex>,
        results: &mut Vec<Vec<ConstraintIndex>>,
    ) {
        let dependency_map = self.dependency_map.as_ref().unwrap();

        // Check if we already visited this region.
        if !visited.insert(current_region) {
            return;
        }

        // Check if we reached the region we were looking for.
        if current_region == to_region {
            // Unless we started out searching for `'a ~> 'a`, which shouldn't have caused
            // en error, then we must have traversed at least *some* constraint:
            assert!(!stack.is_empty());

            // The first constraint should be like `X: from_region`.
            assert_eq!(self.constraints[stack[0]].sub, from_region);

            // The last constraint should be like `to_region: Y`.
            assert_eq!(self.constraints[*stack.last().unwrap()].sup, to_region);

            results.push(stack.clone());
            return;
        }

        self.constraints
            .each_affected_by_dirty(dependency_map[current_region], |constraint| {
                assert_eq!(self.constraints[constraint].sub, current_region);
                stack.push(constraint);
                self.find_constraint_paths_between_regions_helper(
                    from_region,
                    self.constraints[constraint].sup,
                    to_region,
                    visited,
                    stack,
                    results,
                );
                stack.pop();
            });
    }

    /// This function will return true if a constraint is interesting and false if a constraint
    /// is not. It is useful in filtering constraint paths to only interesting points.
    fn constraint_is_interesting(&self, index: ConstraintIndex) -> bool {
        let constraint = self.constraints[index];
        debug!(
            "constraint_is_interesting: locations={:?} constraint={:?}",
            constraint.locations, constraint
        );
        if let Locations::Interesting(_) = constraint.locations {
            true
        } else {
            false
        }
    }

    /// This function classifies a constraint from a location.
    fn classify_constraint(
        &self,
        index: ConstraintIndex,
        mir: &Mir<'tcx>,
    ) -> Option<(ConstraintCategory, Span)> {
        let constraint = self.constraints[index];
        let span = constraint.locations.span(mir);
        let location = constraint.locations.from_location()?;

        if !self.constraint_is_interesting(index) {
            return Some((ConstraintCategory::Boring, span));
        }

        let data = &mir[location.block];
        let category = if location.statement_index == data.statements.len() {
            if let Some(ref terminator) = data.terminator {
                match terminator.kind {
                    TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment,
                    TerminatorKind::Call { .. } => ConstraintCategory::CallArgument,
                    _ => ConstraintCategory::Other,
                }
            } else {
                ConstraintCategory::Other
            }
        } else {
            let statement = &data.statements[location.statement_index];
            match statement.kind {
                StatementKind::Assign(ref place, ref rvalue) => {
                    if *place == Place::Local(mir::RETURN_PLACE) {
                        ConstraintCategory::Return
                    } else {
                        match rvalue {
                            Rvalue::Cast(..) => ConstraintCategory::Cast,
                            Rvalue::Use(..) => ConstraintCategory::Assignment,
                            _ => ConstraintCategory::Other,
                        }
                    }
                }
                _ => ConstraintCategory::Other,
            }
        };

        Some((category, span))
    }

    /// Report an error because the universal region `fr` was required to outlive
    /// `outlived_fr` but it is not known to do so. For example:
    ///
    /// ```
    /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
    /// ```
    ///
    /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
    pub(super) fn report_error(
        &self,
        mir: &Mir<'tcx>,
        infcx: &InferCtxt<'_, '_, 'tcx>,
        mir_def_id: DefId,
        fr: RegionVid,
        outlived_fr: RegionVid,
        blame_span: Span,
    ) {
        debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);

        let fr_name = self.to_error_region(fr);
        let outlived_fr_name = self.to_error_region(outlived_fr);

        if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) {
            let tables = infcx.tcx.typeck_tables_of(mir_def_id);
            let nice = NiceRegionError::new_from_span(infcx.tcx, blame_span, o, f, Some(tables));
            if let Some(_error_reported) = nice.try_report() {
                return;
            }
        }

        let fr_string = match fr_name {
            Some(r) => format!("free region `{}`", r),
            None => format!("free region `{:?}`", fr),
        };

        let outlived_fr_string = match outlived_fr_name {
            Some(r) => format!("free region `{}`", r),
            None => format!("free region `{:?}`", outlived_fr),
        };

        // Find all paths
        let constraint_paths = self.find_constraint_paths_between_regions(outlived_fr, fr);
        debug!("report_error: constraint_paths={:#?}", constraint_paths);

        // Find the shortest such path.
        let path = constraint_paths.iter().min_by_key(|p| p.len()).unwrap();
        debug!("report_error: shortest_path={:?}", path);

        // Classify each of the constraints along the path.
        let mut categorized_path: Vec<(ConstraintCategory, Span)> = path.iter()
            .filter_map(|&index| self.classify_constraint(index, mir))
            .collect();
        debug!("report_error: categorized_path={:?}", categorized_path);

        // Find what appears to be the most interesting path to report to the user.
        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
        debug!("report_error: sorted_path={:?}", categorized_path);

        // If we found something, cite that as the main cause of the problem.
        if let Some((category, span)) = categorized_path.first() {
            let mut diag = infcx.tcx.sess.struct_span_err(
                *span,
                &format!(
                    "{} requires that data must outlive {}",
                    category, outlived_fr_string
                ),
            );

            diag.emit();
        } else {
            let mut diag = infcx.tcx.sess.struct_span_err(
                blame_span,
                &format!("{} does not outlive {}", fr_string, outlived_fr_string,),
            );

            diag.emit();
        }
    }

    // Find some constraint `X: Y` where:
    // - `fr1: X` transitively
    // - and `Y` is live at `elem`
    crate fn find_constraint(&self, fr1: RegionVid, elem: Location) -> RegionVid {
        let index = self.blame_constraint(fr1, elem);
        self.constraints[index].sub
    }

    /// Tries to finds a good span to blame for the fact that `fr1`
    /// contains `fr2`.
    pub(super) fn blame_constraint(
        &self,
        fr1: RegionVid,
        elem: impl ToElementIndex,
    ) -> ConstraintIndex {
        // Find everything that influenced final value of `fr`.
        let influenced_fr1 = self.dependencies(fr1);

        // Try to find some outlives constraint `'X: fr2` where `'X`
        // influenced `fr1`. Blame that.
        //
        // NB, this is a pretty bad choice most of the time. In
        // particular, the connection between `'X` and `fr1` may not
        // be obvious to the user -- not to mention the naive notion
        // of dependencies, which doesn't account for the locations of
        // contraints at all. But it will do for now.
        let relevant_constraint = self.constraints
            .iter_enumerated()
            .filter_map(|(i, constraint)| {
                if !self.liveness_constraints.contains(constraint.sub, elem) {
                    None
                } else {
                    influenced_fr1[constraint.sup]
                        .map(|distance| (distance, i))
                }
            })
            .min() // constraining fr1 with fewer hops *ought* to be more obvious
            .map(|(_dist, i)| i);

        relevant_constraint.unwrap_or_else(|| {
            bug!(
                "could not find any constraint to blame for {:?}: {:?}",
                fr1,
                elem,
            );
        })
    }

    /// Finds all regions whose values `'a` may depend on in some way.
    /// For each region, returns either `None` (does not influence
    /// `'a`) or `Some(d)` which indicates that it influences `'a`
    /// with distinct `d` (minimum number of edges that must be
    /// traversed).
    ///
    /// Used during error reporting, extremely naive and inefficient.
    fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> {
        let mut result_set = IndexVec::from_elem(None, &self.definitions);
        let mut changed = true;
        result_set[r0] = Some(0); // distance 0 from `r0`

        while changed {
            changed = false;
            for constraint in &*self.constraints {
                if let Some(n) = result_set[constraint.sup] {
                    let m = n + 1;
                    if result_set[constraint.sub]
                        .map(|distance| m < distance)
                        .unwrap_or(true)
                    {
                        result_set[constraint.sub] = Some(m);
                        changed = true;
                    }
                }
            }
        }

        result_set
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2014 Y. T. CHUNG <zonyitoo@gmail.com>

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::sync::Arc;
// use std::sync::atomic::{AtomicOption, SeqCst};
use std::net::lookup_host;
use std::net::{SocketAddr, ToSocketAddrs};
use std::io;
use std::vec::IntoIter;

use simplesched::Scheduler;
use simplesched::sync::Mutex;

use lru_cache::LruCache;

struct DnsLruCache {
    cache: LruCache<String, Vec<SocketAddr>>,
    totally_matched: usize,
    totally_missed: usize,
}

pub struct CachedDns {
    lru_cache: Arc<Mutex<DnsLruCache>>,
}

impl CachedDns {
    pub fn with_capacity(cache_capacity: usize) -> CachedDns {
        CachedDns {
            lru_cache: Arc::new(Mutex::new(DnsLruCache {
                cache: LruCache::new(cache_capacity),
                totally_missed: 0,
                totally_matched: 0,
            })),
        }
    }

    pub fn resolve(&self, addr_str: &str) -> Option<Vec<SocketAddr>> {
        {
            let mut cache = self.lru_cache.lock().unwrap();
            match cache.cache.get(addr_str).map(|x| x.clone()) {
                Some(addrs) => {
                    cache.totally_matched += 1;
                    debug!("DNS cache matched!: {}", addr_str);
                    debug!("DNS cache matched: {}, missed: {}", cache.totally_matched, cache.totally_missed);
                    return Some(addrs)
                },
                None => {
                    cache.totally_missed += 1;
                    debug!("DNS cache missed!: {}", addr_str);
                    debug!("DNS cache matched: {}, missed: {}", cache.totally_matched, cache.totally_missed);
                }
            }
        }

        let addrs = match lookup_host(addr_str) {
            Ok(addrs) => addrs,
            Err(err) => {
                error!("Failed to resolve {}: {}", addr_str, err);
                return None;
            }
        };

        let cloned_mutex = self.lru_cache.clone();

        let mut addr_vec = Vec::new();
        let mut last_err: io::Result<()> = Ok(());
        for sock_addr in addrs {
            match sock_addr {
                Ok(addr) => {
                    addr_vec.push(addr);
                },
                Err(err) => last_err = Err(err),
            }
        }

        if addr_vec.is_empty() && last_err.is_err() {
            error!("Failed to resolve {}: {:?}", addr_str, last_err.unwrap_err());
            return None;
        }
        let cloned_addrs = addr_vec.clone();

        let addr_string: String = addr_str.to_owned();
        Scheduler::spawn(move || {
            let mut cache = cloned_mutex.lock().unwrap();
            cache.cache.insert(addr_string, cloned_addrs);
        });
        Some(addr_vec)
    }
}

unsafe impl Send for CachedDns {}
unsafe impl Sync for CachedDns {}
<commit_msg>fixed warning in cached dns<commit_after>// The MIT License (MIT)

// Copyright (c) 2014 Y. T. CHUNG <zonyitoo@gmail.com>

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::sync::Arc;
// use std::sync::atomic::{AtomicOption, SeqCst};
use std::net::lookup_host;
use std::net::SocketAddr;
use std::io;

use simplesched::Scheduler;
use simplesched::sync::Mutex;

use lru_cache::LruCache;

struct DnsLruCache {
    cache: LruCache<String, Vec<SocketAddr>>,
    totally_matched: usize,
    totally_missed: usize,
}

pub struct CachedDns {
    lru_cache: Arc<Mutex<DnsLruCache>>,
}

impl CachedDns {
    pub fn with_capacity(cache_capacity: usize) -> CachedDns {
        CachedDns {
            lru_cache: Arc::new(Mutex::new(DnsLruCache {
                cache: LruCache::new(cache_capacity),
                totally_missed: 0,
                totally_matched: 0,
            })),
        }
    }

    pub fn resolve(&self, addr_str: &str) -> Option<Vec<SocketAddr>> {
        {
            let mut cache = self.lru_cache.lock().unwrap();
            match cache.cache.get(addr_str).map(|x| x.clone()) {
                Some(addrs) => {
                    cache.totally_matched += 1;
                    debug!("DNS cache matched!: {}", addr_str);
                    debug!("DNS cache matched: {}, missed: {}", cache.totally_matched, cache.totally_missed);
                    return Some(addrs)
                },
                None => {
                    cache.totally_missed += 1;
                    debug!("DNS cache missed!: {}", addr_str);
                    debug!("DNS cache matched: {}, missed: {}", cache.totally_matched, cache.totally_missed);
                }
            }
        }

        let addrs = match lookup_host(addr_str) {
            Ok(addrs) => addrs,
            Err(err) => {
                error!("Failed to resolve {}: {}", addr_str, err);
                return None;
            }
        };

        let cloned_mutex = self.lru_cache.clone();

        let mut addr_vec = Vec::new();
        let mut last_err: io::Result<()> = Ok(());
        for sock_addr in addrs {
            match sock_addr {
                Ok(addr) => {
                    addr_vec.push(addr);
                },
                Err(err) => last_err = Err(err),
            }
        }

        if addr_vec.is_empty() && last_err.is_err() {
            error!("Failed to resolve {}: {:?}", addr_str, last_err.unwrap_err());
            return None;
        }
        let cloned_addrs = addr_vec.clone();

        let addr_string: String = addr_str.to_owned();
        Scheduler::spawn(move || {
            let mut cache = cloned_mutex.lock().unwrap();
            cache.cache.insert(addr_string, cloned_addrs);
        });
        Some(addr_vec)
    }
}

unsafe impl Send for CachedDns {}
unsafe impl Sync for CachedDns {}
<|endoftext|>


<commit_before><commit_msg>Add default values for various power level attributes.<commit_after><|endoftext|>


<commit_before><commit_msg>Test #[allow(unused)] on `if` expression<commit_after>// check-pass

fn main() {
    #[allow(unused_variables)]
    if true {
        let a = 1;
    } else if false {
        let b = 1;
    } else {
        let c = 1;
    }
}
<|endoftext|>


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

// Regression test for #29740. Inefficient MIR matching algorithms
// generated way too much code for this sort of case, leading to OOM.

pub mod KeyboardEventConstants {
    pub const DOM_KEY_LOCATION_STANDARD: u32 = 0;
    pub const DOM_KEY_LOCATION_LEFT: u32 = 1;
    pub const DOM_KEY_LOCATION_RIGHT: u32 = 2;
    pub const DOM_KEY_LOCATION_NUMPAD: u32 = 3;
} // mod KeyboardEventConstants

pub enum Key {
    Space,
    Apostrophe,
    Comma,
    Minus,
    Period,
    Slash,
    Num0,
    Num1,
    Num2,
    Num3,
    Num4,
    Num5,
    Num6,
    Num7,
    Num8,
    Num9,
    Semicolon,
    Equal,
    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z,
    LeftBracket,
    Backslash,
    RightBracket,
    GraveAccent,
    World1,
    World2,

    Escape,
    Enter,
    Tab,
    Backspace,
    Insert,
    Delete,
    Right,
    Left,
    Down,
    Up,
    PageUp,
    PageDown,
    Home,
    End,
    CapsLock,
    ScrollLock,
    NumLock,
    PrintScreen,
    Pause,
    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,
    F16,
    F17,
    F18,
    F19,
    F20,
    F21,
    F22,
    F23,
    F24,
    F25,
    Kp0,
    Kp1,
    Kp2,
    Kp3,
    Kp4,
    Kp5,
    Kp6,
    Kp7,
    Kp8,
    Kp9,
    KpDecimal,
    KpDivide,
    KpMultiply,
    KpSubtract,
    KpAdd,
    KpEnter,
    KpEqual,
    LeftShift,
    LeftControl,
    LeftAlt,
    LeftSuper,
    RightShift,
    RightControl,
    RightAlt,
    RightSuper,
    Menu,
}

fn key_from_string(key_string: &str, location: u32) -> Option<Key> {
    match key_string {
        " " => Some(Key::Space),
        "\"" => Some(Key::Apostrophe),
        "'" => Some(Key::Apostrophe),
        "<" => Some(Key::Comma),
        "," => Some(Key::Comma),
        "_" => Some(Key::Minus),
        "-" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Minus),
        ">" => Some(Key::Period),
        "." if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Period),
        "?" => Some(Key::Slash),
        "/" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Slash),
        "~" => Some(Key::GraveAccent),
        "`" => Some(Key::GraveAccent),
        ")" => Some(Key::Num0),
        "0" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num0),
        "!" => Some(Key::Num1),
        "1" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num1),
        "@" => Some(Key::Num2),
        "2" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num2),
        "#" => Some(Key::Num3),
        "3" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num3),
        "$" => Some(Key::Num4),
        "4" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num4),
        "%" => Some(Key::Num5),
        "5" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num5),
        "^" => Some(Key::Num6),
        "6" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num6),
        "&" => Some(Key::Num7),
        "7" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num7),
        "*" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num8),
        "8" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num8),
        "(" => Some(Key::Num9),
        "9" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num9),
        ":" => Some(Key::Semicolon),
        ";" => Some(Key::Semicolon),
        "+" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Equal),
        "=" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Equal),
        "A" => Some(Key::A),
        "a" => Some(Key::A),
        "B" => Some(Key::B),
        "b" => Some(Key::B),
        "C" => Some(Key::C),
        "c" => Some(Key::C),
        "D" => Some(Key::D),
        "d" => Some(Key::D),
        "E" => Some(Key::E),
        "e" => Some(Key::E),
        "F" => Some(Key::F),
        "f" => Some(Key::F),
        "G" => Some(Key::G),
        "g" => Some(Key::G),
        "H" => Some(Key::H),
        "h" => Some(Key::H),
        "I" => Some(Key::I),
        "i" => Some(Key::I),
        "J" => Some(Key::J),
        "j" => Some(Key::J),
        "K" => Some(Key::K),
        "k" => Some(Key::K),
        "L" => Some(Key::L),
        "l" => Some(Key::L),
        "M" => Some(Key::M),
        "m" => Some(Key::M),
        "N" => Some(Key::N),
        "n" => Some(Key::N),
        "O" => Some(Key::O),
        "o" => Some(Key::O),
        "P" => Some(Key::P),
        "p" => Some(Key::P),
        "Q" => Some(Key::Q),
        "q" => Some(Key::Q),
        "R" => Some(Key::R),
        "r" => Some(Key::R),
        "S" => Some(Key::S),
        "s" => Some(Key::S),
        "T" => Some(Key::T),
        "t" => Some(Key::T),
        "U" => Some(Key::U),
        "u" => Some(Key::U),
        "V" => Some(Key::V),
        "v" => Some(Key::V),
        "W" => Some(Key::W),
        "w" => Some(Key::W),
        "X" => Some(Key::X),
        "x" => Some(Key::X),
        "Y" => Some(Key::Y),
        "y" => Some(Key::Y),
        "Z" => Some(Key::Z),
        "z" => Some(Key::Z),
        "{" => Some(Key::LeftBracket),
        "[" => Some(Key::LeftBracket),
        "|" => Some(Key::Backslash),
        "\\" => Some(Key::Backslash),
        "}" => Some(Key::RightBracket),
        "]" => Some(Key::RightBracket),
        "Escape" => Some(Key::Escape),
        "Enter" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Enter),
        "Tab" => Some(Key::Tab),
        "Backspace" => Some(Key::Backspace),
        "Insert" => Some(Key::Insert),
        "Delete" => Some(Key::Delete),
        "ArrowRight" => Some(Key::Right),
        "ArrowLeft" => Some(Key::Left),
        "ArrowDown" => Some(Key::Down),
        "ArrowUp" => Some(Key::Up),
        "PageUp" => Some(Key::PageUp),
        "PageDown" => Some(Key::PageDown),
        "Home" => Some(Key::Home),
        "End" => Some(Key::End),
        "CapsLock" => Some(Key::CapsLock),
        "ScrollLock" => Some(Key::ScrollLock),
        "NumLock" => Some(Key::NumLock),
        "PrintScreen" => Some(Key::PrintScreen),
        "Pause" => Some(Key::Pause),
        "F1" => Some(Key::F1),
        "F2" => Some(Key::F2),
        "F3" => Some(Key::F3),
        "F4" => Some(Key::F4),
        "F5" => Some(Key::F5),
        "F6" => Some(Key::F6),
        "F7" => Some(Key::F7),
        "F8" => Some(Key::F8),
        "F9" => Some(Key::F9),
        "F10" => Some(Key::F10),
        "F11" => Some(Key::F11),
        "F12" => Some(Key::F12),
        "F13" => Some(Key::F13),
        "F14" => Some(Key::F14),
        "F15" => Some(Key::F15),
        "F16" => Some(Key::F16),
        "F17" => Some(Key::F17),
        "F18" => Some(Key::F18),
        "F19" => Some(Key::F19),
        "F20" => Some(Key::F20),
        "F21" => Some(Key::F21),
        "F22" => Some(Key::F22),
        "F23" => Some(Key::F23),
        "F24" => Some(Key::F24),
        "F25" => Some(Key::F25),
        "0" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp0),
        "1" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp1),
        "2" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp2),
        "3" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp3),
        "4" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp4),
        "5" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp5),
        "6" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp6),
        "7" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp7),
        "8" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp8),
        "9" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp9),
        "." if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpDecimal),
        "/" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpDivide),
        "*" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpMultiply),
        "-" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpSubtract),
        "+" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpAdd),
        "Enter" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpEnter),
        "=" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpEqual),
        "Shift" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT => Some(Key::LeftShift),
        "Control" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT => Some(Key::LeftControl),
        "Alt" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT => Some(Key::LeftAlt),
        "Super" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT => Some(Key::LeftSuper),
        "Shift" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT => Some(Key::RightShift),
        "Control" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT => Some(Key::RightControl),
        "Alt" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT => Some(Key::RightAlt),
        "Super" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT => Some(Key::RightSuper),
        "ContextMenu" => Some(Key::Menu),
        _ => None
    }
}

fn main() { }
<commit_msg>ignore pretty since it dies for some mysterious reason I can't be bothered to track down for a regresson test. /me hopes no one notices<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Regression test for #29740. Inefficient MIR matching algorithms
// generated way too much code for this sort of case, leading to OOM.

// ignore-pretty

pub mod KeyboardEventConstants {
    pub const DOM_KEY_LOCATION_STANDARD: u32 = 0;
    pub const DOM_KEY_LOCATION_LEFT: u32 = 1;
    pub const DOM_KEY_LOCATION_RIGHT: u32 = 2;
    pub const DOM_KEY_LOCATION_NUMPAD: u32 = 3;
} // mod KeyboardEventConstants

pub enum Key {
    Space,
    Apostrophe,
    Comma,
    Minus,
    Period,
    Slash,
    Num0,
    Num1,
    Num2,
    Num3,
    Num4,
    Num5,
    Num6,
    Num7,
    Num8,
    Num9,
    Semicolon,
    Equal,
    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z,
    LeftBracket,
    Backslash,
    RightBracket,
    GraveAccent,
    World1,
    World2,

    Escape,
    Enter,
    Tab,
    Backspace,
    Insert,
    Delete,
    Right,
    Left,
    Down,
    Up,
    PageUp,
    PageDown,
    Home,
    End,
    CapsLock,
    ScrollLock,
    NumLock,
    PrintScreen,
    Pause,
    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,
    F16,
    F17,
    F18,
    F19,
    F20,
    F21,
    F22,
    F23,
    F24,
    F25,
    Kp0,
    Kp1,
    Kp2,
    Kp3,
    Kp4,
    Kp5,
    Kp6,
    Kp7,
    Kp8,
    Kp9,
    KpDecimal,
    KpDivide,
    KpMultiply,
    KpSubtract,
    KpAdd,
    KpEnter,
    KpEqual,
    LeftShift,
    LeftControl,
    LeftAlt,
    LeftSuper,
    RightShift,
    RightControl,
    RightAlt,
    RightSuper,
    Menu,
}

fn key_from_string(key_string: &str, location: u32) -> Option<Key> {
    match key_string {
        " " => Some(Key::Space),
        "\"" => Some(Key::Apostrophe),
        "'" => Some(Key::Apostrophe),
        "<" => Some(Key::Comma),
        "," => Some(Key::Comma),
        "_" => Some(Key::Minus),
        "-" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Minus),
        ">" => Some(Key::Period),
        "." if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Period),
        "?" => Some(Key::Slash),
        "/" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Slash),
        "~" => Some(Key::GraveAccent),
        "`" => Some(Key::GraveAccent),
        ")" => Some(Key::Num0),
        "0" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num0),
        "!" => Some(Key::Num1),
        "1" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num1),
        "@" => Some(Key::Num2),
        "2" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num2),
        "#" => Some(Key::Num3),
        "3" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num3),
        "$" => Some(Key::Num4),
        "4" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num4),
        "%" => Some(Key::Num5),
        "5" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num5),
        "^" => Some(Key::Num6),
        "6" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num6),
        "&" => Some(Key::Num7),
        "7" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num7),
        "*" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num8),
        "8" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num8),
        "(" => Some(Key::Num9),
        "9" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Num9),
        ":" => Some(Key::Semicolon),
        ";" => Some(Key::Semicolon),
        "+" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Equal),
        "=" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Equal),
        "A" => Some(Key::A),
        "a" => Some(Key::A),
        "B" => Some(Key::B),
        "b" => Some(Key::B),
        "C" => Some(Key::C),
        "c" => Some(Key::C),
        "D" => Some(Key::D),
        "d" => Some(Key::D),
        "E" => Some(Key::E),
        "e" => Some(Key::E),
        "F" => Some(Key::F),
        "f" => Some(Key::F),
        "G" => Some(Key::G),
        "g" => Some(Key::G),
        "H" => Some(Key::H),
        "h" => Some(Key::H),
        "I" => Some(Key::I),
        "i" => Some(Key::I),
        "J" => Some(Key::J),
        "j" => Some(Key::J),
        "K" => Some(Key::K),
        "k" => Some(Key::K),
        "L" => Some(Key::L),
        "l" => Some(Key::L),
        "M" => Some(Key::M),
        "m" => Some(Key::M),
        "N" => Some(Key::N),
        "n" => Some(Key::N),
        "O" => Some(Key::O),
        "o" => Some(Key::O),
        "P" => Some(Key::P),
        "p" => Some(Key::P),
        "Q" => Some(Key::Q),
        "q" => Some(Key::Q),
        "R" => Some(Key::R),
        "r" => Some(Key::R),
        "S" => Some(Key::S),
        "s" => Some(Key::S),
        "T" => Some(Key::T),
        "t" => Some(Key::T),
        "U" => Some(Key::U),
        "u" => Some(Key::U),
        "V" => Some(Key::V),
        "v" => Some(Key::V),
        "W" => Some(Key::W),
        "w" => Some(Key::W),
        "X" => Some(Key::X),
        "x" => Some(Key::X),
        "Y" => Some(Key::Y),
        "y" => Some(Key::Y),
        "Z" => Some(Key::Z),
        "z" => Some(Key::Z),
        "{" => Some(Key::LeftBracket),
        "[" => Some(Key::LeftBracket),
        "|" => Some(Key::Backslash),
        "\\" => Some(Key::Backslash),
        "}" => Some(Key::RightBracket),
        "]" => Some(Key::RightBracket),
        "Escape" => Some(Key::Escape),
        "Enter" if location == KeyboardEventConstants::DOM_KEY_LOCATION_STANDARD => Some(Key::Enter),
        "Tab" => Some(Key::Tab),
        "Backspace" => Some(Key::Backspace),
        "Insert" => Some(Key::Insert),
        "Delete" => Some(Key::Delete),
        "ArrowRight" => Some(Key::Right),
        "ArrowLeft" => Some(Key::Left),
        "ArrowDown" => Some(Key::Down),
        "ArrowUp" => Some(Key::Up),
        "PageUp" => Some(Key::PageUp),
        "PageDown" => Some(Key::PageDown),
        "Home" => Some(Key::Home),
        "End" => Some(Key::End),
        "CapsLock" => Some(Key::CapsLock),
        "ScrollLock" => Some(Key::ScrollLock),
        "NumLock" => Some(Key::NumLock),
        "PrintScreen" => Some(Key::PrintScreen),
        "Pause" => Some(Key::Pause),
        "F1" => Some(Key::F1),
        "F2" => Some(Key::F2),
        "F3" => Some(Key::F3),
        "F4" => Some(Key::F4),
        "F5" => Some(Key::F5),
        "F6" => Some(Key::F6),
        "F7" => Some(Key::F7),
        "F8" => Some(Key::F8),
        "F9" => Some(Key::F9),
        "F10" => Some(Key::F10),
        "F11" => Some(Key::F11),
        "F12" => Some(Key::F12),
        "F13" => Some(Key::F13),
        "F14" => Some(Key::F14),
        "F15" => Some(Key::F15),
        "F16" => Some(Key::F16),
        "F17" => Some(Key::F17),
        "F18" => Some(Key::F18),
        "F19" => Some(Key::F19),
        "F20" => Some(Key::F20),
        "F21" => Some(Key::F21),
        "F22" => Some(Key::F22),
        "F23" => Some(Key::F23),
        "F24" => Some(Key::F24),
        "F25" => Some(Key::F25),
        "0" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp0),
        "1" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp1),
        "2" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp2),
        "3" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp3),
        "4" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp4),
        "5" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp5),
        "6" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp6),
        "7" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp7),
        "8" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp8),
        "9" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::Kp9),
        "." if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpDecimal),
        "/" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpDivide),
        "*" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpMultiply),
        "-" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpSubtract),
        "+" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpAdd),
        "Enter" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpEnter),
        "=" if location == KeyboardEventConstants::DOM_KEY_LOCATION_NUMPAD => Some(Key::KpEqual),
        "Shift" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT => Some(Key::LeftShift),
        "Control" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT => Some(Key::LeftControl),
        "Alt" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT => Some(Key::LeftAlt),
        "Super" if location == KeyboardEventConstants::DOM_KEY_LOCATION_LEFT => Some(Key::LeftSuper),
        "Shift" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT => Some(Key::RightShift),
        "Control" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT => Some(Key::RightControl),
        "Alt" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT => Some(Key::RightAlt),
        "Super" if location == KeyboardEventConstants::DOM_KEY_LOCATION_RIGHT => Some(Key::RightSuper),
        "ContextMenu" => Some(Key::Menu),
        _ => None
    }
}

fn main() { }
<|endoftext|>


<commit_before><commit_msg>Move thread handle in function<commit_after><|endoftext|>


<commit_before><commit_msg>Add tests for annotated call times.<commit_after><|endoftext|>


<commit_before><commit_msg>Coalesce a few calls to epoll_ctl<commit_after><|endoftext|>


<commit_before>use std::cell::{Cell, RefCell};
use std::io::{self, ErrorKind};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use std::sync::mpsc;

use mio;
use slab::Slab;
use futures::{Future, Tokens, Wake};

pub type Source = Arc<mio::Evented + Send + Sync>;

static NEXT_LOOP_ID: AtomicUsize = ATOMIC_USIZE_INIT;
scoped_thread_local!(static CURRENT_LOOP: Loop);

const SLAB_CAPACITY: usize = 1024 * 64;

pub struct Loop {
    id: usize,
    active: Cell<bool>,
    io: RefCell<mio::Poll>,
    tx: mio::channel::Sender<Message>,
    rx: mio::channel::Receiver<Message>,
    dispatch: RefCell<Slab<Scheduled, usize>>,
}

/// Handle to an event loop, used to construct I/O objects, send messages, and
/// otherwise interact indirectly with the event loop itself.
///
/// Handles can be cloned, and when cloned they will still refer to the
/// same underlying event loop.
#[derive(Clone)]
pub struct LoopHandle {
    id: usize,
    tx: mio::channel::Sender<Message>,
}

#[derive(Copy, Clone)]
pub enum Direction {
    Read,
    Write,
}

struct Scheduled {
    source: Source,
    reader: Option<Arc<Wake>>,
    writer: Option<Arc<Wake>>,
}

impl Scheduled {
    fn waiter_for(&mut self, dir: Direction) -> &mut Option<Arc<Wake>> {
        match dir {
            Direction::Read => &mut self.reader,
            Direction::Write => &mut self.writer,
        }
    }

    fn event_set(&self) -> mio::EventSet {
        let mut set = mio::EventSet::none();
        if self.reader.is_some() {
            set = set | mio::EventSet::readable()
        }
        if self.writer.is_some() {
            set = set | mio::EventSet::writable()
        }
        set
    }
}

enum Message {
    AddSource(Source, Arc<AtomicUsize>, Arc<Wake>),
    DropSource(usize),
    Schedule(usize, Direction, Arc<Wake>),
    Deschedule(usize, Direction),
    Shutdown,
}

fn register(poll: &mut mio::Poll, token: usize, sched: &Scheduled) {
    // TODO: handle error
    poll.register(&*sched.source,
                  mio::Token(token),
                  mio::EventSet::none(),
                  mio::PollOpt::level())
        .unwrap();
}

fn reregister(poll: &mut mio::Poll, token: usize, sched: &Scheduled) {
    // TODO: handle error
    poll.reregister(&*sched.source,
                    mio::Token(token),
                    sched.event_set(),
                    mio::PollOpt::edge() | mio::PollOpt::oneshot())
        .unwrap();
}

fn deregister(poll: &mut mio::Poll, sched: &Scheduled) {
    // TODO: handle error
    poll.deregister(&*sched.source).unwrap();
}

impl Loop {
    pub fn new() -> io::Result<Loop> {
        let (tx, rx) = mio::channel::from_std_channel(mpsc::channel());
        let io = try!(mio::Poll::new());
        try!(io.register(&rx,
                         mio::Token(0),
                         mio::EventSet::readable(),
                         mio::PollOpt::edge()));
        Ok(Loop {
            id: NEXT_LOOP_ID.fetch_add(1, Ordering::Relaxed),
            active: Cell::new(true),
            io: RefCell::new(io),
            tx: tx,
            rx: rx,
            dispatch: RefCell::new(Slab::new_starting_at(1, SLAB_CAPACITY)),
        })
    }

    pub fn handle(&self) -> LoopHandle {
        LoopHandle {
            id: self.id,
            tx: self.tx.clone(),
        }
    }

    pub fn run<F: Future>(self, f: F) -> Result<F::Item, F::Error> {
        let (tx_res, rx_res) = mpsc::channel();
        let handle = self.handle();
        f.then(move |res| {
            handle.shutdown();
            tx_res.send(res)
        }).forget();

        while self.active.get() {
            let amt;
            // On Linux, Poll::poll is epoll_wait, which may return EINTR if a
            // ptracer attaches. This retry loop prevents crashing when
            // attaching strace, or similar.
            loop {
                match self.io.borrow_mut().poll(None) {
                    Ok(a) => {
                        amt = a;
                        break;
                    }
                    Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
                    err @ Err(_) => {
                        err.unwrap();
                    }
                }
            }

            // TODO: coalesce token sets for a given Wake?
            for i in 0..amt {
                let event = self.io.borrow_mut().events().get(i).unwrap();
                let token = event.token().as_usize();
                if token == 0 {
                    self.consume_queue();
                } else {
                    let mut reader = None;
                    let mut writer = None;

                    if let Some(sched) = self.dispatch.borrow_mut().get_mut(token) {
                        if event.kind().is_readable() {
                            reader = sched.reader.take();
                        }

                        if event.kind().is_writable() {
                            writer = sched.writer.take();
                        }
                    }

                    CURRENT_LOOP.set(&self, || {
                        if let Some(reader_wake) = reader.take() {
                            reader_wake.wake(&Tokens::from_usize(token));
                        }
                        if let Some(writer_wake) = writer.take() {
                            writer_wake.wake(&Tokens::from_usize(token));
                        }
                    });

                    // For now, always reregister, to deal with the fact that
                    // combined oneshot + read|write requires rearming even if
                    // only one side fired.
                    //
                    // TODO: optimize this
                    if let Some(sched) = self.dispatch.borrow().get(token) {
                        reregister(&mut self.io.borrow_mut(), token, &sched);
                    }
                }
            }
        }

        rx_res.recv().unwrap()
    }

    fn add_source(&self, source: Source) -> usize {
        let sched = Scheduled {
            source: source,
            reader: None,
            writer: None,
        };
        let mut dispatch = self.dispatch.borrow_mut();
        // TODO: handle out of space
        let entry = dispatch.vacant_entry().unwrap();
        register(&mut self.io.borrow_mut(), entry.index(), &sched);
        entry.insert(sched).index()
    }

    fn drop_source(&self, token: usize) {
        let sched = self.dispatch.borrow_mut().remove(token).unwrap();
        deregister(&mut self.io.borrow_mut(), &sched);
    }

    fn schedule(&self, token: usize, dir: Direction, wake: Arc<Wake>) {
        let mut dispatch = self.dispatch.borrow_mut();
        let sched = dispatch.get_mut(token).unwrap();
        *sched.waiter_for(dir) = Some(wake);
        reregister(&mut self.io.borrow_mut(), token, sched);
    }

    fn deschedule(&self, token: usize, dir: Direction) {
        let mut dispatch = self.dispatch.borrow_mut();
        let sched = dispatch.get_mut(token).unwrap();
        *sched.waiter_for(dir) = None;
        reregister(&mut self.io.borrow_mut(), token, sched);
    }

    fn consume_queue(&self) {
        while let Ok(msg) = self.rx.try_recv() {
            self.notify(msg);
        }
    }

    fn notify(&self, msg: Message) {
        match msg {
            Message::AddSource(source, id, wake) => {
                let tok = self.add_source(source);
                id.store(tok, Ordering::Relaxed);
                wake.wake(&Tokens::from_usize(ADD_SOURCE_TOKEN));
            }
            Message::DropSource(tok) => self.drop_source(tok),
            Message::Schedule(tok, dir, wake) => self.schedule(tok, dir, wake),
            Message::Deschedule(tok, dir) => self.deschedule(tok, dir),
            Message::Shutdown => self.active.set(false),
        }
    }
}

impl LoopHandle {
    fn send(&self, msg: Message) {
        let mut msg_dance = Some(msg);

        if CURRENT_LOOP.is_set() {
            CURRENT_LOOP.with(|lp| {
                if lp.id == self.id {
                    // Need to execute all existing requests first, to ensure
                    // that our message is processed "in order"
                    lp.consume_queue();
                    lp.notify(msg_dance.take().unwrap());
                }
            })
        }

        if let Some(msg) = msg_dance.take() {
            self.tx
                .send(msg)
                .map_err(|_| ())
                .expect("failed to send register message") // todo: handle failure
        }
    }

    /// Add a new source to an event loop, returning a future which will resolve
    /// to the token that can be used to identify this source.
    ///
    /// When a new I/O object is created it needs to be communicated to the
    /// event loop to ensure that it's registered and ready to receive
    /// notifications. The event loop with then respond with a unique token that
    /// this handle can be identified with (the resolved value of the returned
    /// future).
    ///
    /// This token is then passed in turn to each of the methods below to
    /// interact with notifications on the I/O object itself.
    pub fn add_source(&self, source: Source) -> AddSource {
        AddSource {
            loop_handle: self.clone(),
            source: Some(source),
            id: Arc::new(AtomicUsize::new(0)),
            scheduled: false,
        }
    }

    fn add_source_(&self, source: Source, id: Arc<AtomicUsize>, wake: Arc<Wake>) {
        self.send(Message::AddSource(source, id, wake));
    }

    /// Begin listening for events on an event loop.
    ///
    /// Once an I/O object has been registered with the event loop through the
    /// `add_source` method, this method can be used with the assigned token to
    /// begin awaiting notifications.
    ///
    /// The `dir` argument indicates how the I/O object is expected to be
    /// awaited on (either readable or writable) and the `wake` callback will be
    /// invoked. Note that one the `wake` callback is invoked once it will not
    /// be invoked again, it must be re-`schedule`d to continue receiving
    /// notifications.
    pub fn schedule(&self, tok: usize, dir: Direction, wake: Arc<Wake>) {
        self.send(Message::Schedule(tok, dir, wake));
    }

    /// Stop listening for events on an event loop.
    ///
    /// Once a callback has been scheduled with the `schedule` method, it can be
    /// unregistered from the event loop with this method. This method does not
    /// guarantee that the callback will not be invoked if it hasn't already,
    /// but a best effort will be made to ensure it is not called.
    pub fn deschedule(&self, tok: usize, dir: Direction) {
        self.send(Message::Deschedule(tok, dir));
    }

    /// Unregister all information associated with a token on an event loop,
    /// deallocating all internal resources assigned to the given token.
    ///
    /// This method should be called whenever a source of events is being
    /// destroyed. This will ensure that the event loop can reuse `tok` for
    /// another I/O object if necessary and also remove it from any poll
    /// notifications and callbacks.
    ///
    /// Note that wake callbacks may still be invoked after this method is
    /// called as it may take some time for the message to drop a source to
    /// reach the event loop. Despite this fact, this method will attempt to
    /// ensure that the callbacks are **not** invoked, so pending scheduled
    /// callbacks cannot be relied upon to get called.
    pub fn drop_source(&self, tok: usize) {
        self.send(Message::DropSource(tok));
    }

    pub fn shutdown(&self) {
        self.send(Message::Shutdown);
    }
}

const ADD_SOURCE_TOKEN: usize = 0;

/// A future which will resolve a unique `tok` token for an I/O object.
///
/// Created through the `LoopHandle::add_source` method, this future can also
/// resolve to an error if there's an issue communicating with the event loop.
pub struct AddSource {
    loop_handle: LoopHandle,
    source: Option<Source>,
    id: Arc<AtomicUsize>,
    scheduled: bool,
}

impl Future for AddSource {
    type Item = usize;
    type Error = io::Error; // TODO: integrate channel error?

    fn poll(&mut self, tokens: &Tokens) -> Option<Result<usize, io::Error>> {
        if self.scheduled {
            if tokens.may_contain(&Tokens::from_usize(ADD_SOURCE_TOKEN)) {
                let id = self.id.load(Ordering::Relaxed);
                if id != 0 {
                    return Some(Ok(id))
                }
            }
        } else {
            if CURRENT_LOOP.is_set() {
                let res = CURRENT_LOOP.with(|lp| {
                    if lp.id == self.loop_handle.id {
                        Some(lp.add_source(self.source.take().unwrap()))
                    } else {
                        None
                    }
                });
                if let Some(id) = res {
                    return Some(Ok(id));
                }
            }
        }

        None
    }

    fn schedule(&mut self, wake: Arc<Wake>) {
        if self.scheduled { return; }
        self.scheduled = true;
        self.loop_handle.add_source_(self.source.take().unwrap(), self.id.clone(), wake);
    }
}
<commit_msg>Add a convenience method to get the Loop<commit_after>use std::cell::{Cell, RefCell};
use std::io::{self, ErrorKind};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use std::sync::mpsc;

use mio;
use slab::Slab;
use futures::{Future, Tokens, Wake};

pub type Source = Arc<mio::Evented + Send + Sync>;

static NEXT_LOOP_ID: AtomicUsize = ATOMIC_USIZE_INIT;
scoped_thread_local!(static CURRENT_LOOP: Loop);

const SLAB_CAPACITY: usize = 1024 * 64;

pub struct Loop {
    id: usize,
    active: Cell<bool>,
    io: RefCell<mio::Poll>,
    tx: mio::channel::Sender<Message>,
    rx: mio::channel::Receiver<Message>,
    dispatch: RefCell<Slab<Scheduled, usize>>,
}

/// Handle to an event loop, used to construct I/O objects, send messages, and
/// otherwise interact indirectly with the event loop itself.
///
/// Handles can be cloned, and when cloned they will still refer to the
/// same underlying event loop.
#[derive(Clone)]
pub struct LoopHandle {
    id: usize,
    tx: mio::channel::Sender<Message>,
}

#[derive(Copy, Clone)]
pub enum Direction {
    Read,
    Write,
}

struct Scheduled {
    source: Source,
    reader: Option<Arc<Wake>>,
    writer: Option<Arc<Wake>>,
}

impl Scheduled {
    fn waiter_for(&mut self, dir: Direction) -> &mut Option<Arc<Wake>> {
        match dir {
            Direction::Read => &mut self.reader,
            Direction::Write => &mut self.writer,
        }
    }

    fn event_set(&self) -> mio::EventSet {
        let mut set = mio::EventSet::none();
        if self.reader.is_some() {
            set = set | mio::EventSet::readable()
        }
        if self.writer.is_some() {
            set = set | mio::EventSet::writable()
        }
        set
    }
}

enum Message {
    AddSource(Source, Arc<AtomicUsize>, Arc<Wake>),
    DropSource(usize),
    Schedule(usize, Direction, Arc<Wake>),
    Deschedule(usize, Direction),
    Shutdown,
}

fn register(poll: &mut mio::Poll, token: usize, sched: &Scheduled) {
    // TODO: handle error
    poll.register(&*sched.source,
                  mio::Token(token),
                  mio::EventSet::none(),
                  mio::PollOpt::level())
        .unwrap();
}

fn reregister(poll: &mut mio::Poll, token: usize, sched: &Scheduled) {
    // TODO: handle error
    poll.reregister(&*sched.source,
                    mio::Token(token),
                    sched.event_set(),
                    mio::PollOpt::edge() | mio::PollOpt::oneshot())
        .unwrap();
}

fn deregister(poll: &mut mio::Poll, sched: &Scheduled) {
    // TODO: handle error
    poll.deregister(&*sched.source).unwrap();
}

impl Loop {
    pub fn new() -> io::Result<Loop> {
        let (tx, rx) = mio::channel::from_std_channel(mpsc::channel());
        let io = try!(mio::Poll::new());
        try!(io.register(&rx,
                         mio::Token(0),
                         mio::EventSet::readable(),
                         mio::PollOpt::edge()));
        Ok(Loop {
            id: NEXT_LOOP_ID.fetch_add(1, Ordering::Relaxed),
            active: Cell::new(true),
            io: RefCell::new(io),
            tx: tx,
            rx: rx,
            dispatch: RefCell::new(Slab::new_starting_at(1, SLAB_CAPACITY)),
        })
    }

    pub fn handle(&self) -> LoopHandle {
        LoopHandle {
            id: self.id,
            tx: self.tx.clone(),
        }
    }

    pub fn run<F: Future>(self, f: F) -> Result<F::Item, F::Error> {
        let (tx_res, rx_res) = mpsc::channel();
        let handle = self.handle();
        f.then(move |res| {
            handle.shutdown();
            tx_res.send(res)
        }).forget();

        while self.active.get() {
            let amt;
            // On Linux, Poll::poll is epoll_wait, which may return EINTR if a
            // ptracer attaches. This retry loop prevents crashing when
            // attaching strace, or similar.
            loop {
                match self.io.borrow_mut().poll(None) {
                    Ok(a) => {
                        amt = a;
                        break;
                    }
                    Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
                    err @ Err(_) => {
                        err.unwrap();
                    }
                }
            }

            // TODO: coalesce token sets for a given Wake?
            for i in 0..amt {
                let event = self.io.borrow_mut().events().get(i).unwrap();
                let token = event.token().as_usize();
                if token == 0 {
                    self.consume_queue();
                } else {
                    let mut reader = None;
                    let mut writer = None;

                    if let Some(sched) = self.dispatch.borrow_mut().get_mut(token) {
                        if event.kind().is_readable() {
                            reader = sched.reader.take();
                        }

                        if event.kind().is_writable() {
                            writer = sched.writer.take();
                        }
                    }

                    CURRENT_LOOP.set(&self, || {
                        if let Some(reader_wake) = reader.take() {
                            reader_wake.wake(&Tokens::from_usize(token));
                        }
                        if let Some(writer_wake) = writer.take() {
                            writer_wake.wake(&Tokens::from_usize(token));
                        }
                    });

                    // For now, always reregister, to deal with the fact that
                    // combined oneshot + read|write requires rearming even if
                    // only one side fired.
                    //
                    // TODO: optimize this
                    if let Some(sched) = self.dispatch.borrow().get(token) {
                        reregister(&mut self.io.borrow_mut(), token, &sched);
                    }
                }
            }
        }

        rx_res.recv().unwrap()
    }

    fn add_source(&self, source: Source) -> usize {
        let sched = Scheduled {
            source: source,
            reader: None,
            writer: None,
        };
        let mut dispatch = self.dispatch.borrow_mut();
        // TODO: handle out of space
        let entry = dispatch.vacant_entry().unwrap();
        register(&mut self.io.borrow_mut(), entry.index(), &sched);
        entry.insert(sched).index()
    }

    fn drop_source(&self, token: usize) {
        let sched = self.dispatch.borrow_mut().remove(token).unwrap();
        deregister(&mut self.io.borrow_mut(), &sched);
    }

    fn schedule(&self, token: usize, dir: Direction, wake: Arc<Wake>) {
        let mut dispatch = self.dispatch.borrow_mut();
        let sched = dispatch.get_mut(token).unwrap();
        *sched.waiter_for(dir) = Some(wake);
        reregister(&mut self.io.borrow_mut(), token, sched);
    }

    fn deschedule(&self, token: usize, dir: Direction) {
        let mut dispatch = self.dispatch.borrow_mut();
        let sched = dispatch.get_mut(token).unwrap();
        *sched.waiter_for(dir) = None;
        reregister(&mut self.io.borrow_mut(), token, sched);
    }

    fn consume_queue(&self) {
        while let Ok(msg) = self.rx.try_recv() {
            self.notify(msg);
        }
    }

    fn notify(&self, msg: Message) {
        match msg {
            Message::AddSource(source, id, wake) => {
                let tok = self.add_source(source);
                id.store(tok, Ordering::Relaxed);
                wake.wake(&Tokens::from_usize(ADD_SOURCE_TOKEN));
            }
            Message::DropSource(tok) => self.drop_source(tok),
            Message::Schedule(tok, dir, wake) => self.schedule(tok, dir, wake),
            Message::Deschedule(tok, dir) => self.deschedule(tok, dir),
            Message::Shutdown => self.active.set(false),
        }
    }
}

impl LoopHandle {
    fn send(&self, msg: Message) {
        self.with_loop(|lp| {
            match lp {
                Some(lp) => {
                    // Need to execute all existing requests first, to ensure
                    // that our message is processed "in order"
                    lp.consume_queue();
                    lp.notify(msg);
                }
                None => {
                    // TODO: handle failure
                    self.tx
                        .send(msg)
                        .map_err(|_| ())
                        .expect("failed to send register message")
                }
            }
        })
    }

    fn with_loop<F, R>(&self, f: F) -> R
        where F: FnOnce(Option<&Loop>) -> R
    {
        if CURRENT_LOOP.is_set() {
            CURRENT_LOOP.with(|lp| {
                if lp.id == self.id {
                    f(Some(lp))
                } else {
                    f(None)
                }
            })
        } else {
            f(None)
        }
    }

    /// Add a new source to an event loop, returning a future which will resolve
    /// to the token that can be used to identify this source.
    ///
    /// When a new I/O object is created it needs to be communicated to the
    /// event loop to ensure that it's registered and ready to receive
    /// notifications. The event loop with then respond with a unique token that
    /// this handle can be identified with (the resolved value of the returned
    /// future).
    ///
    /// This token is then passed in turn to each of the methods below to
    /// interact with notifications on the I/O object itself.
    pub fn add_source(&self, source: Source) -> AddSource {
        AddSource {
            loop_handle: self.clone(),
            source: Some(source),
            id: Arc::new(AtomicUsize::new(0)),
            scheduled: false,
        }
    }

    fn add_source_(&self, source: Source, id: Arc<AtomicUsize>, wake: Arc<Wake>) {
        self.send(Message::AddSource(source, id, wake));
    }

    /// Begin listening for events on an event loop.
    ///
    /// Once an I/O object has been registered with the event loop through the
    /// `add_source` method, this method can be used with the assigned token to
    /// begin awaiting notifications.
    ///
    /// The `dir` argument indicates how the I/O object is expected to be
    /// awaited on (either readable or writable) and the `wake` callback will be
    /// invoked. Note that one the `wake` callback is invoked once it will not
    /// be invoked again, it must be re-`schedule`d to continue receiving
    /// notifications.
    pub fn schedule(&self, tok: usize, dir: Direction, wake: Arc<Wake>) {
        self.send(Message::Schedule(tok, dir, wake));
    }

    /// Stop listening for events on an event loop.
    ///
    /// Once a callback has been scheduled with the `schedule` method, it can be
    /// unregistered from the event loop with this method. This method does not
    /// guarantee that the callback will not be invoked if it hasn't already,
    /// but a best effort will be made to ensure it is not called.
    pub fn deschedule(&self, tok: usize, dir: Direction) {
        self.send(Message::Deschedule(tok, dir));
    }

    /// Unregister all information associated with a token on an event loop,
    /// deallocating all internal resources assigned to the given token.
    ///
    /// This method should be called whenever a source of events is being
    /// destroyed. This will ensure that the event loop can reuse `tok` for
    /// another I/O object if necessary and also remove it from any poll
    /// notifications and callbacks.
    ///
    /// Note that wake callbacks may still be invoked after this method is
    /// called as it may take some time for the message to drop a source to
    /// reach the event loop. Despite this fact, this method will attempt to
    /// ensure that the callbacks are **not** invoked, so pending scheduled
    /// callbacks cannot be relied upon to get called.
    pub fn drop_source(&self, tok: usize) {
        self.send(Message::DropSource(tok));
    }

    pub fn shutdown(&self) {
        self.send(Message::Shutdown);
    }
}

const ADD_SOURCE_TOKEN: usize = 0;

/// A future which will resolve a unique `tok` token for an I/O object.
///
/// Created through the `LoopHandle::add_source` method, this future can also
/// resolve to an error if there's an issue communicating with the event loop.
pub struct AddSource {
    loop_handle: LoopHandle,
    source: Option<Source>,
    id: Arc<AtomicUsize>,
    scheduled: bool,
}

impl Future for AddSource {
    type Item = usize;
    type Error = io::Error; // TODO: integrate channel error?

    fn poll(&mut self, tokens: &Tokens) -> Option<Result<usize, io::Error>> {
        if self.scheduled {
            if tokens.may_contain(&Tokens::from_usize(ADD_SOURCE_TOKEN)) {
                let id = self.id.load(Ordering::Relaxed);
                if id != 0 {
                    return Some(Ok(id))
                }
            }
        } else {
            if CURRENT_LOOP.is_set() {
                let res = CURRENT_LOOP.with(|lp| {
                    if lp.id == self.loop_handle.id {
                        Some(lp.add_source(self.source.take().unwrap()))
                    } else {
                        None
                    }
                });
                if let Some(id) = res {
                    return Some(Ok(id));
                }
            }
        }

        None
    }

    fn schedule(&mut self, wake: Arc<Wake>) {
        if self.scheduled { return; }
        self.scheduled = true;
        self.loop_handle.add_source_(self.source.take().unwrap(), self.id.clone(), wake);
    }
}
<|endoftext|>


<commit_before><commit_msg>Auto merge of #1696 - RalfJung:abi-check, r=RalfJung<commit_after>fn main() {
    extern "Rust" {
        fn malloc(size: usize) -> *mut std::ffi::c_void;
    }

    unsafe {
        let _ = malloc(0); //~ ERROR calling a function with ABI C using caller ABI Rust
    };
}
<|endoftext|>


<commit_before><commit_msg>Day 10 part 1 and 2<commit_after>// advent10.rs
// parsing instructions for chip factory

#[macro_use]
extern crate lazy_static;
extern crate regex;

use std::io;
use std::io::BufRead;
use regex::Regex;

fn main() {
    let stdin = io::stdin();
    let mut factory = Factory::new();

    for line in stdin.lock().lines().map(|l| l.expect("Failed to read line")) {
        // part 1
        factory.parse_instruction(&line);
        // part 2
        factory.parse_instruction2(&line);
    }

    // part 1
    if let Some(bot_id) = factory.find_comparison(61, 17) {
        println!("part 1 bot ID {}", bot_id);
    } else {
        println!("part 1 bot not found!");
    }

    // part 2
    let product = factory.get_output_val(0) * factory.get_output_val(1) * factory.get_output_val(2);
    println!("part 2 output product {}", product);
}

#[derive(Debug, PartialEq, Clone)]
enum Chip {
    Unassigned,
    BotLow(usize),
    BotHigh(usize),
    Val(usize),
}

struct Factory {
    chip0: Vec<Chip>,
    chip1: Vec<Chip>,
    outputs: Vec<Chip>,
}

impl Factory {
    fn new() -> Factory {
        Factory {
            chip0: Vec::new(),
            chip1: Vec::new(),
            outputs: Vec::new(),
        }
    }

    // no need to parse outputs since they aren't used for the answer to part 1
    fn parse_instruction(&mut self, instr: &str) {
        lazy_static! {
            static ref RE_VAL: Regex = Regex::new(r"^value (\d+) goes to bot (\d+)").unwrap();
            static ref RE_BOT_LOW: Regex = Regex::new(r"^bot (\d+).+low to bot (\d+)").unwrap();
            static ref RE_BOT_HIGH: Regex = Regex::new(r"^bot (\d+).+high to bot (\d+)").unwrap();
        }
        if let Some(caps) = RE_VAL.captures(instr) {
            let val: usize = caps.at(1).unwrap().parse().unwrap();
            let bot_id: usize = caps.at(2).unwrap().parse().unwrap();
            self.give_chip_to_bot(bot_id, Chip::Val(val));
        } else {
            if let Some(caps) = RE_BOT_LOW.captures(instr) {
                let src_bot: usize = caps.at(1).unwrap().parse().unwrap();
                let dest_bot: usize = caps.at(2).unwrap().parse().unwrap();
                self.give_chip_to_bot(dest_bot, Chip::BotLow(src_bot));
            }
            if let Some(caps) = RE_BOT_HIGH.captures(instr) {
                let src_bot: usize = caps.at(1).unwrap().parse().unwrap();
                let dest_bot: usize = caps.at(2).unwrap().parse().unwrap();
                self.give_chip_to_bot(dest_bot, Chip::BotHigh(src_bot));
            }
        }
    }

    fn give_chip_to_bot(&mut self, bot_id: usize, chip: Chip) {
        if bot_id >= self.chip0.len() {
            self.chip0.resize(bot_id + 1, Chip::Unassigned);
            self.chip1.resize(bot_id + 1, Chip::Unassigned);
        }

        let chip0 = &mut self.chip0[bot_id];
        let chip1 = &mut self.chip1[bot_id];

        if *chip0 == Chip::Unassigned {
            *chip0 = chip;
        } else if *chip1 == Chip::Unassigned {
            *chip1 = chip;
        } else {
            panic!("Bot {} received {:?}, but was already holding {:?} and {:?}",
                   bot_id,
                   chip,
                   chip0,
                   chip1);
        }
    }

    fn get_chip_val(&mut self, bot_id: usize, chip0: bool) -> usize {
        let chip = if chip0 {
            self.chip0[bot_id].clone()
        } else {
            self.chip1[bot_id].clone()
        };

        let chip_val = match chip {
            Chip::Val(new_val) => new_val,
            Chip::BotLow(low_bot) => {
                std::cmp::min(self.get_chip_val(low_bot, false),
                              self.get_chip_val(low_bot, true))
            }
            Chip::BotHigh(high_bot) => {
                std::cmp::max(self.get_chip_val(high_bot, false),
                              self.get_chip_val(high_bot, true))
            }
            _ => panic!("Attempting to get uninitialized chip from bot {}", bot_id),
        };

        // not strictly necessary but should be more efficient if we cache the result
        if chip0 {
            self.chip0[bot_id] = Chip::Val(chip_val);
        } else {
            self.chip1[bot_id] = Chip::Val(chip_val);
        }

        chip_val
    }

    // find the bot that compares val0 and val1
    fn find_comparison(&mut self, val0: usize, val1: usize) -> Option<usize> {
        for bot_id in 0..self.chip0.len() {
            let chip_val0 = self.get_chip_val(bot_id, true);
            let chip_val1 = self.get_chip_val(bot_id, false);
            if chip_val0 == val0 && chip_val1 == val1 || (chip_val0 == val1 && chip_val1 == val0) {
                return Some(bot_id);
            }
        }

        None
    }

    // ///////
    // Part 2
    fn parse_instruction2(&mut self, instr: &str) {
        lazy_static! {
            static ref RE_OUT_LOW: Regex = Regex::new(r"^bot (\d+).+low to output (\d+)").unwrap();
            static ref RE_OUT_HIGH: Regex = Regex::new(r"^bot (\d+).+high to output (\d+)").unwrap();
        }
        if let Some(caps) = RE_OUT_LOW.captures(instr) {
            let bot: usize = caps.at(1).unwrap().parse().unwrap();
            let output: usize = caps.at(2).unwrap().parse().unwrap();
            self.assign_chip_to_output(output, Chip::BotLow(bot));
        }
        if let Some(caps) = RE_OUT_HIGH.captures(instr) {
            let bot: usize = caps.at(1).unwrap().parse().unwrap();
            let output: usize = caps.at(2).unwrap().parse().unwrap();
            self.assign_chip_to_output(output, Chip::BotHigh(bot));
        }
    }

    fn assign_chip_to_output(&mut self, output_id: usize, chip: Chip) {
        if output_id >= self.outputs.len() {
            self.outputs.resize(output_id + 1, Chip::Unassigned);
        }

        let output_chip = &mut self.outputs[output_id];

        if *output_chip == Chip::Unassigned {
            *output_chip = chip;
        } else {
            panic!("Output {} received {:?}, but was already holding {:?}",
                   output_id,
                   chip,
                   output_chip);
        }
    }

    fn get_output_val(&mut self, output_id: usize) -> usize {
        let chip = self.outputs[output_id].clone();

        match chip {
            Chip::BotLow(low_bot) => {
                std::cmp::min(self.get_chip_val(low_bot, false),
                              self.get_chip_val(low_bot, true))
            }
            Chip::BotHigh(high_bot) => {
                std::cmp::max(self.get_chip_val(high_bot, false),
                              self.get_chip_val(high_bot, true))
            }
            Chip::Val(new_val) => new_val,
            _ => panic!("Tried to read uninitialized output {}", output_id),
        }
    }
}

// //////
// Tests
#[test]
fn test_get_chip_val() {
    let mut b = Factory::new();
    b.give_chip_to_bot(3, Chip::Val(9));
    b.give_chip_to_bot(3, Chip::Val(10));
    b.give_chip_to_bot(1, Chip::BotHigh(3));
    b.give_chip_to_bot(5, Chip::BotLow(3));

    assert_eq!(9, b.get_chip_val(3, true));
    assert_eq!(10, b.get_chip_val(3, false));
    assert_eq!(10, b.get_chip_val(1, true));
    assert_eq!(9, b.get_chip_val(5, true));
}

#[test]
fn test_give_chip_to_bot() {
    let mut b = Factory::new();
    b.give_chip_to_bot(2, Chip::Val(5));
    b.give_chip_to_bot(1, Chip::BotLow(2));
    b.give_chip_to_bot(0, Chip::BotHigh(2));
    b.give_chip_to_bot(1, Chip::Val(3));
    b.give_chip_to_bot(0, Chip::BotHigh(1));
    b.give_chip_to_bot(2, Chip::Val(2));

    assert_eq!(Some(2), b.find_comparison(5, 2));
    assert_eq!(Some(2), b.find_comparison(2, 5));
}

#[test]
fn test_parse_instruction() {
    let mut b = Factory::new();
    b.parse_instruction("value 5 goes to bot 2");
    b.parse_instruction("bot 2 gives low to bot 1 and high to bot 0");
    b.parse_instruction("value 3 goes to bot 1");
    b.parse_instruction("bot 1 gives low to output 1 and high to bot 0");
    b.parse_instruction("bot 0 gives low to output 2 and high to output 0");
    b.parse_instruction("value 2 goes to bot 2");

    assert_eq!(Some(2), b.find_comparison(5, 2));
    assert_eq!(Some(2), b.find_comparison(2, 5));
}

// part 2
#[test]
fn test_parse_instruction2() {
    let mut b = Factory::new();
    b.parse_instruction("value 5 goes to bot 2");
    b.parse_instruction("bot 2 gives low to bot 1 and high to bot 0");
    b.parse_instruction("value 3 goes to bot 1");
    b.parse_instruction("bot 1 gives low to output 1 and high to bot 0");
    b.parse_instruction("bot 0 gives low to output 2 and high to output 0");
    b.parse_instruction("value 2 goes to bot 2");
    b.parse_instruction2("value 5 goes to bot 2");
    b.parse_instruction2("bot 2 gives low to bot 1 and high to bot 0");
    b.parse_instruction2("value 3 goes to bot 1");
    b.parse_instruction2("bot 1 gives low to output 1 and high to bot 0");
    b.parse_instruction2("bot 0 gives low to output 2 and high to output 0");
    b.parse_instruction2("value 2 goes to bot 2");

    assert_eq!(Some(2), b.find_comparison(5, 2));
    assert_eq!(Some(2), b.find_comparison(2, 5));
    assert_eq!(5, b.get_output_val(0));
    assert_eq!(2, b.get_output_val(1));
    assert_eq!(3, b.get_output_val(2));
}
<|endoftext|>


<commit_before><commit_msg>Add rust knapsack problem<commit_after>// n = number of items we have left to consider
// c = capacity we have left
fn knapsack(memo: &mut Vec<Vec<Option<usize>>>,
            w: &Vec<usize>,
            v: &Vec<usize>,
            n: usize,
            c: usize) -> usize {
    if let Some(r) = memo[n][c] {
        return r;
    }

    let result;

    if n == 0 || c == 0 {
        result = 0;
    } else if w[n] > c {
        result = knapsack(memo, w, v, n-1, c);
    } else {
        let tmp1 = knapsack(memo, w, v, n-1, c);
        let tmp2 = v[n] + knapsack(memo, w, v, n-1, c - w[n]);
        result = if tmp1 > tmp2 { tmp1 } else { tmp2 };
    }

    memo[n][c] = Some(result);
    result
}

fn main() {
    let weights = vec![1, 2, 4, 2, 5];
    let values = vec![5, 3, 5, 3, 2];

    let n = weights.len() - 1;

    let capacity: usize = 10;

    let mut memo = vec![vec![None; capacity + 1]; n + 1];

    println!("Optimal value: {}", knapsack(&mut memo,
                                           &weights,
                                           &values,
                                           n,
                                           capacity));
}
<|endoftext|>