<commit_before>// Copyright 2012-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::borrow_set::{BorrowSet, BorrowData};
use borrow_check::place_ext::PlaceExt;

use rustc;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::middle::region;
use rustc::mir::{self, Location, Place, Mir};
use rustc::ty::TyCtxt;
use rustc::ty::RegionKind;
use rustc::ty::RegionKind::ReScope;

use rustc_data_structures::bitslice::BitwiseOperator;
use rustc_data_structures::indexed_set::IdxSet;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::sync::Lrc;

use dataflow::{BitDenotation, BlockSets, InitialFlow};
pub use dataflow::indexes::BorrowIndex;
use borrow_check::nll::region_infer::RegionInferenceContext;
use borrow_check::nll::ToRegionVid;

use std::rc::Rc;

/// `Borrows` stores the data used in the analyses that track the flow
/// of borrows.
///
/// It uniquely identifies every borrow (`Rvalue::Ref`) by a
/// `BorrowIndex`, and maps each such index to a `BorrowData`
/// describing the borrow. These indexes are used for representing the
/// borrows in compact bitvectors.
pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'gcx, 'tcx>,
    mir: &'a Mir<'tcx>,
    scope_tree: Lrc<region::ScopeTree>,
    root_scope: Option<region::Scope>,

    borrow_set: Rc<BorrowSet<'tcx>>,

    /// NLL region inference context with which NLL queries should be resolved
    nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
}

impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
    crate fn new(
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        mir: &'a Mir<'tcx>,
        nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
        def_id: DefId,
        body_id: Option<hir::BodyId>,
        borrow_set: &Rc<BorrowSet<'tcx>>
    ) -> Self {
        let scope_tree = tcx.region_scope_tree(def_id);
        let root_scope = body_id.map(|body_id| {
            region::Scope::CallSite(tcx.hir.body(body_id).value.hir_id.local_id)
        });

        Borrows {
            tcx: tcx,
            mir: mir,
            borrow_set: borrow_set.clone(),
            scope_tree,
            root_scope,
            nonlexical_regioncx,
        }
    }

    crate fn borrows(&self) -> &IndexVec<BorrowIndex, BorrowData<'tcx>> { &self.borrow_set.borrows }

    pub fn scope_tree(&self) -> &Lrc<region::ScopeTree> { &self.scope_tree }

    pub fn location(&self, idx: BorrowIndex) -> &Location {
        &self.borrow_set.borrows[idx].reserve_location
    }

    /// Add all borrows to the kill set, if those borrows are out of scope at `location`.
    /// That means either they went out of either a nonlexical scope, if we care about those
    /// at the moment, or the location represents a lexical EndRegion
    fn kill_loans_out_of_scope_at_location(&self,
                                           sets: &mut BlockSets<BorrowIndex>,
                                           location: Location) {
        let regioncx = &self.nonlexical_regioncx;

        // NOTE: The state associated with a given `location`
        // reflects the dataflow on entry to the statement. If it
        // does not contain `borrow_region`, then then that means
        // that the statement at `location` kills the borrow.
        //
        // We are careful always to call this function *before* we
        // set up the gen-bits for the statement or
        // termanator. That way, if the effect of the statement or
        // terminator *does* introduce a new loan of the same
        // region, then setting that gen-bit will override any
        // potential kill introduced here.
        for (borrow_index, borrow_data) in self.borrow_set.borrows.iter_enumerated() {
            let borrow_region = borrow_data.region.to_region_vid();
            if !regioncx.region_contains_point(borrow_region, location) {
                sets.kill(&borrow_index);
            }
        }
    }

    fn kill_borrows_on_local(&self,
                             sets: &mut BlockSets<BorrowIndex>,
                             local: &rustc::mir::Local)
    {
        if let Some(borrow_indexes) = self.borrow_set.local_map.get(local) {
            sets.kill_all(borrow_indexes);
        }
    }
}

impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
    type Idx = BorrowIndex;
    fn name() -> &'static str { "borrows" }
    fn bits_per_block(&self) -> usize {
        self.borrow_set.borrows.len() * 2
    }

    fn start_block_effect(&self, _entry_set: &mut IdxSet<BorrowIndex>) {
        // no borrows of code region_scopes have been taken prior to
        // function execution, so this method has no effect on
        // `_sets`.
    }

    fn before_statement_effect(&self,
                               sets: &mut BlockSets<BorrowIndex>,
                               location: Location) {
        debug!("Borrows::before_statement_effect sets: {:?} location: {:?}", sets, location);
        self.kill_loans_out_of_scope_at_location(sets, location);
    }

    fn statement_effect(&self, sets: &mut BlockSets<BorrowIndex>, location: Location) {
        debug!("Borrows::statement_effect sets: {:?} location: {:?}", sets, location);

        let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
            panic!("could not find block at location {:?}", location);
        });
        let stmt = block.statements.get(location.statement_index).unwrap_or_else(|| {
            panic!("could not find statement at location {:?}");
        });

        self.kill_loans_out_of_scope_at_location(sets, location);

        match stmt.kind {
            mir::StatementKind::EndRegion(_) => {
            }

            mir::StatementKind::Assign(ref lhs, ref rhs) => {
                // Make sure there are no remaining borrows for variables
                // that are assigned over.
                if let Place::Local(ref local) = *lhs {
                    // FIXME: Handle the case in which we're assigning over
                    // a projection (`foo.bar`).
                    self.kill_borrows_on_local(sets, local);
                }

                // NOTE: if/when the Assign case is revised to inspect
                // the assigned_place here, make sure to also
                // re-consider the current implementations of the
                // propagate_call_return method.

                if let mir::Rvalue::Ref(region, _, ref place) = *rhs {
                    if place.is_unsafe_place(self.tcx, self.mir) { return; }
                    let index = self.borrow_set.location_map.get(&location).unwrap_or_else(|| {
                        panic!("could not find BorrowIndex for location {:?}", location);
                    });

                    if let RegionKind::ReEmpty = region {
                        // If the borrowed value dies before the borrow is used, the region for
                        // the borrow can be empty. Don't track the borrow in that case.
                        debug!("Borrows::statement_effect_on_borrows \
                                location: {:?} stmt: {:?} has empty region, killing {:?}",
                               location, stmt.kind, index);
                        sets.kill(&index);
                        return
                    } else {
                        debug!("Borrows::statement_effect_on_borrows location: {:?} stmt: {:?}",
                               location, stmt.kind);
                    }

                    assert!(self.borrow_set.region_map.get(region).unwrap_or_else(|| {
                        panic!("could not find BorrowIndexs for region {:?}", region);
                    }).contains(&index));
                    sets.gen(&index);

                    // Issue #46746: Two-phase borrows handles
                    // stmts of form `Tmp = &mut Borrow` ...
                    match lhs {
                        Place::Local(..) | Place::Static(..) => {} // okay
                        Place::Projection(..) => {
                            // ... can assign into projections,
                            // e.g. `box (&mut _)`. Current
                            // conservative solution: force
                            // immediate activation here.
                            sets.gen(&index);
                        }
                    }
                }
            }

            mir::StatementKind::StorageDead(local) => {
                // Make sure there are no remaining borrows for locals that
                // are gone out of scope.
                self.kill_borrows_on_local(sets, &local)
            }

            mir::StatementKind::InlineAsm { ref outputs, ref asm, .. } => {
                for (output, kind) in outputs.iter().zip(&asm.outputs) {
                    if !kind.is_indirect && !kind.is_rw {
                        // Make sure there are no remaining borrows for direct
                        // output variables.
                        if let Place::Local(ref local) = *output {
                            // FIXME: Handle the case in which we're assigning over
                            // a projection (`foo.bar`).
                            self.kill_borrows_on_local(sets, local);
                        }
                    }
                }
            }

            mir::StatementKind::SetDiscriminant { .. } |
            mir::StatementKind::StorageLive(..) |
            mir::StatementKind::Validate(..) |
            mir::StatementKind::UserAssertTy(..) |
            mir::StatementKind::Nop => {}

        }
    }

    fn before_terminator_effect(&self,
                                sets: &mut BlockSets<BorrowIndex>,
                                location: Location) {
        debug!("Borrows::before_terminator_effect sets: {:?} location: {:?}", sets, location);
        self.kill_loans_out_of_scope_at_location(sets, location);
    }

    fn terminator_effect(&self, sets: &mut BlockSets<BorrowIndex>, location: Location) {
        debug!("Borrows::terminator_effect sets: {:?} location: {:?}", sets, location);

        let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
            panic!("could not find block at location {:?}", location);
        });

        let term = block.terminator();
        self.kill_loans_out_of_scope_at_location(sets, location);

        match term.kind {
            mir::TerminatorKind::Resume |
            mir::TerminatorKind::Return |
            mir::TerminatorKind::GeneratorDrop => {
                // When we return from the function, then all `ReScope`-style regions
                // are guaranteed to have ended.
                // Normally, there would be `EndRegion` statements that come before,
                // and hence most of these loans will already be dead -- but, in some cases
                // like unwind paths, we do not always emit `EndRegion` statements, so we
                // add some kills here as a "backup" and to avoid spurious error messages.
                for (borrow_index, borrow_data) in self.borrow_set.borrows.iter_enumerated() {
                    if let ReScope(scope) = borrow_data.region {
                        // Check that the scope is not actually a scope from a function that is
                        // a parent of our closure. Note that the CallSite scope itself is
                        // *outside* of the closure, for some weird reason.
                        if let Some(root_scope) = self.root_scope {
                            if *scope != root_scope &&
                                self.scope_tree.is_subscope_of(*scope, root_scope)
                            {
                                sets.kill(&borrow_index);
                            }
                        }
                    }
                }
            }
            mir::TerminatorKind::Abort |
            mir::TerminatorKind::SwitchInt {..} |
            mir::TerminatorKind::Drop {..} |
            mir::TerminatorKind::DropAndReplace {..} |
            mir::TerminatorKind::Call {..} |
            mir::TerminatorKind::Assert {..} |
            mir::TerminatorKind::Yield {..} |
            mir::TerminatorKind::Goto {..} |
            mir::TerminatorKind::FalseEdges {..} |
            mir::TerminatorKind::FalseUnwind {..} |
            mir::TerminatorKind::Unreachable => {}
        }
    }

    fn propagate_call_return(&self,
                             _in_out: &mut IdxSet<BorrowIndex>,
                             _call_bb: mir::BasicBlock,
                             _dest_bb: mir::BasicBlock,
                             _dest_place: &mir::Place) {
        // there are no effects on borrows from method call return...
        //
        // ... but if overwriting a place can affect flow state, then
        // latter is not true; see NOTE on Assign case in
        // statement_effect_on_borrows.
    }
}

impl<'a, 'gcx, 'tcx> BitwiseOperator for Borrows<'a, 'gcx, 'tcx> {
    #[inline]
    fn join(&self, pred1: usize, pred2: usize) -> usize {
        pred1 | pred2 // union effects of preds when computing reservations
    }
}

impl<'a, 'gcx, 'tcx> InitialFlow for Borrows<'a, 'gcx, 'tcx> {
    #[inline]
    fn bottom_value() -> bool {
        false // bottom = nothing is reserved or activated yet
    }
}

<commit_msg>Auto merge of #50891 - davidtwco:nll-kill-loans-out-of-scope-at-location-reduce-calls, r=pnkfelix<commit_after>// Copyright 2012-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::borrow_set::{BorrowSet, BorrowData};
use borrow_check::place_ext::PlaceExt;

use rustc;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::middle::region;
use rustc::mir::{self, Location, Place, Mir};
use rustc::ty::TyCtxt;
use rustc::ty::RegionKind;
use rustc::ty::RegionKind::ReScope;

use rustc_data_structures::bitslice::BitwiseOperator;
use rustc_data_structures::indexed_set::IdxSet;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::sync::Lrc;

use dataflow::{BitDenotation, BlockSets, InitialFlow};
pub use dataflow::indexes::BorrowIndex;
use borrow_check::nll::region_infer::RegionInferenceContext;
use borrow_check::nll::ToRegionVid;

use std::rc::Rc;

/// `Borrows` stores the data used in the analyses that track the flow
/// of borrows.
///
/// It uniquely identifies every borrow (`Rvalue::Ref`) by a
/// `BorrowIndex`, and maps each such index to a `BorrowData`
/// describing the borrow. These indexes are used for representing the
/// borrows in compact bitvectors.
pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'gcx, 'tcx>,
    mir: &'a Mir<'tcx>,
    scope_tree: Lrc<region::ScopeTree>,
    root_scope: Option<region::Scope>,

    borrow_set: Rc<BorrowSet<'tcx>>,

    /// NLL region inference context with which NLL queries should be resolved
    nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
}

impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
    crate fn new(
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        mir: &'a Mir<'tcx>,
        nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
        def_id: DefId,
        body_id: Option<hir::BodyId>,
        borrow_set: &Rc<BorrowSet<'tcx>>
    ) -> Self {
        let scope_tree = tcx.region_scope_tree(def_id);
        let root_scope = body_id.map(|body_id| {
            region::Scope::CallSite(tcx.hir.body(body_id).value.hir_id.local_id)
        });

        Borrows {
            tcx: tcx,
            mir: mir,
            borrow_set: borrow_set.clone(),
            scope_tree,
            root_scope,
            nonlexical_regioncx,
        }
    }

    crate fn borrows(&self) -> &IndexVec<BorrowIndex, BorrowData<'tcx>> { &self.borrow_set.borrows }

    pub fn scope_tree(&self) -> &Lrc<region::ScopeTree> { &self.scope_tree }

    pub fn location(&self, idx: BorrowIndex) -> &Location {
        &self.borrow_set.borrows[idx].reserve_location
    }

    /// Add all borrows to the kill set, if those borrows are out of scope at `location`.
    /// That means either they went out of either a nonlexical scope, if we care about those
    /// at the moment, or the location represents a lexical EndRegion
    fn kill_loans_out_of_scope_at_location(&self,
                                           sets: &mut BlockSets<BorrowIndex>,
                                           location: Location) {
        let regioncx = &self.nonlexical_regioncx;

        // NOTE: The state associated with a given `location`
        // reflects the dataflow on entry to the statement. If it
        // does not contain `borrow_region`, then then that means
        // that the statement at `location` kills the borrow.
        //
        // We are careful always to call this function *before* we
        // set up the gen-bits for the statement or
        // termanator. That way, if the effect of the statement or
        // terminator *does* introduce a new loan of the same
        // region, then setting that gen-bit will override any
        // potential kill introduced here.
        for (borrow_index, borrow_data) in self.borrow_set.borrows.iter_enumerated() {
            let borrow_region = borrow_data.region.to_region_vid();
            if !regioncx.region_contains_point(borrow_region, location) {
                sets.kill(&borrow_index);
            }
        }
    }

    fn kill_borrows_on_local(&self,
                             sets: &mut BlockSets<BorrowIndex>,
                             local: &rustc::mir::Local)
    {
        if let Some(borrow_indexes) = self.borrow_set.local_map.get(local) {
            sets.kill_all(borrow_indexes);
        }
    }
}

impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
    type Idx = BorrowIndex;
    fn name() -> &'static str { "borrows" }
    fn bits_per_block(&self) -> usize {
        self.borrow_set.borrows.len() * 2
    }

    fn start_block_effect(&self, _entry_set: &mut IdxSet<BorrowIndex>) {
        // no borrows of code region_scopes have been taken prior to
        // function execution, so this method has no effect on
        // `_sets`.
    }

    fn before_statement_effect(&self,
                               sets: &mut BlockSets<BorrowIndex>,
                               location: Location) {
        debug!("Borrows::before_statement_effect sets: {:?} location: {:?}", sets, location);
        self.kill_loans_out_of_scope_at_location(sets, location);
    }

    fn statement_effect(&self, sets: &mut BlockSets<BorrowIndex>, location: Location) {
        debug!("Borrows::statement_effect sets: {:?} location: {:?}", sets, location);

        let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
            panic!("could not find block at location {:?}", location);
        });
        let stmt = block.statements.get(location.statement_index).unwrap_or_else(|| {
            panic!("could not find statement at location {:?}");
        });

        match stmt.kind {
            mir::StatementKind::EndRegion(_) => {
            }

            mir::StatementKind::Assign(ref lhs, ref rhs) => {
                // Make sure there are no remaining borrows for variables
                // that are assigned over.
                if let Place::Local(ref local) = *lhs {
                    // FIXME: Handle the case in which we're assigning over
                    // a projection (`foo.bar`).
                    self.kill_borrows_on_local(sets, local);
                }

                // NOTE: if/when the Assign case is revised to inspect
                // the assigned_place here, make sure to also
                // re-consider the current implementations of the
                // propagate_call_return method.

                if let mir::Rvalue::Ref(region, _, ref place) = *rhs {
                    if place.is_unsafe_place(self.tcx, self.mir) { return; }
                    let index = self.borrow_set.location_map.get(&location).unwrap_or_else(|| {
                        panic!("could not find BorrowIndex for location {:?}", location);
                    });

                    if let RegionKind::ReEmpty = region {
                        // If the borrowed value dies before the borrow is used, the region for
                        // the borrow can be empty. Don't track the borrow in that case.
                        debug!("Borrows::statement_effect_on_borrows \
                                location: {:?} stmt: {:?} has empty region, killing {:?}",
                               location, stmt.kind, index);
                        sets.kill(&index);
                        return
                    } else {
                        debug!("Borrows::statement_effect_on_borrows location: {:?} stmt: {:?}",
                               location, stmt.kind);
                    }

                    assert!(self.borrow_set.region_map.get(region).unwrap_or_else(|| {
                        panic!("could not find BorrowIndexs for region {:?}", region);
                    }).contains(&index));
                    sets.gen(&index);

                    // Issue #46746: Two-phase borrows handles
                    // stmts of form `Tmp = &mut Borrow` ...
                    match lhs {
                        Place::Local(..) | Place::Static(..) => {} // okay
                        Place::Projection(..) => {
                            // ... can assign into projections,
                            // e.g. `box (&mut _)`. Current
                            // conservative solution: force
                            // immediate activation here.
                            sets.gen(&index);
                        }
                    }
                }
            }

            mir::StatementKind::StorageDead(local) => {
                // Make sure there are no remaining borrows for locals that
                // are gone out of scope.
                self.kill_borrows_on_local(sets, &local)
            }

            mir::StatementKind::InlineAsm { ref outputs, ref asm, .. } => {
                for (output, kind) in outputs.iter().zip(&asm.outputs) {
                    if !kind.is_indirect && !kind.is_rw {
                        // Make sure there are no remaining borrows for direct
                        // output variables.
                        if let Place::Local(ref local) = *output {
                            // FIXME: Handle the case in which we're assigning over
                            // a projection (`foo.bar`).
                            self.kill_borrows_on_local(sets, local);
                        }
                    }
                }
            }

            mir::StatementKind::SetDiscriminant { .. } |
            mir::StatementKind::StorageLive(..) |
            mir::StatementKind::Validate(..) |
            mir::StatementKind::UserAssertTy(..) |
            mir::StatementKind::Nop => {}

        }
    }

    fn before_terminator_effect(&self,
                                sets: &mut BlockSets<BorrowIndex>,
                                location: Location) {
        debug!("Borrows::before_terminator_effect sets: {:?} location: {:?}", sets, location);
        self.kill_loans_out_of_scope_at_location(sets, location);
    }

    fn terminator_effect(&self, sets: &mut BlockSets<BorrowIndex>, location: Location) {
        debug!("Borrows::terminator_effect sets: {:?} location: {:?}", sets, location);

        let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
            panic!("could not find block at location {:?}", location);
        });

        let term = block.terminator();
        match term.kind {
            mir::TerminatorKind::Resume |
            mir::TerminatorKind::Return |
            mir::TerminatorKind::GeneratorDrop => {
                // When we return from the function, then all `ReScope`-style regions
                // are guaranteed to have ended.
                // Normally, there would be `EndRegion` statements that come before,
                // and hence most of these loans will already be dead -- but, in some cases
                // like unwind paths, we do not always emit `EndRegion` statements, so we
                // add some kills here as a "backup" and to avoid spurious error messages.
                for (borrow_index, borrow_data) in self.borrow_set.borrows.iter_enumerated() {
                    if let ReScope(scope) = borrow_data.region {
                        // Check that the scope is not actually a scope from a function that is
                        // a parent of our closure. Note that the CallSite scope itself is
                        // *outside* of the closure, for some weird reason.
                        if let Some(root_scope) = self.root_scope {
                            if *scope != root_scope &&
                                self.scope_tree.is_subscope_of(*scope, root_scope)
                            {
                                sets.kill(&borrow_index);
                            }
                        }
                    }
                }
            }
            mir::TerminatorKind::Abort |
            mir::TerminatorKind::SwitchInt {..} |
            mir::TerminatorKind::Drop {..} |
            mir::TerminatorKind::DropAndReplace {..} |
            mir::TerminatorKind::Call {..} |
            mir::TerminatorKind::Assert {..} |
            mir::TerminatorKind::Yield {..} |
            mir::TerminatorKind::Goto {..} |
            mir::TerminatorKind::FalseEdges {..} |
            mir::TerminatorKind::FalseUnwind {..} |
            mir::TerminatorKind::Unreachable => {}
        }
    }

    fn propagate_call_return(&self,
                             _in_out: &mut IdxSet<BorrowIndex>,
                             _call_bb: mir::BasicBlock,
                             _dest_bb: mir::BasicBlock,
                             _dest_place: &mir::Place) {
        // there are no effects on borrows from method call return...
        //
        // ... but if overwriting a place can affect flow state, then
        // latter is not true; see NOTE on Assign case in
        // statement_effect_on_borrows.
    }
}

impl<'a, 'gcx, 'tcx> BitwiseOperator for Borrows<'a, 'gcx, 'tcx> {
    #[inline]
    fn join(&self, pred1: usize, pred2: usize) -> usize {
        pred1 | pred2 // union effects of preds when computing reservations
    }
}

impl<'a, 'gcx, 'tcx> InitialFlow for Borrows<'a, 'gcx, 'tcx> {
    #[inline]
    fn bottom_value() -> bool {
        false // bottom = nothing is reserved or activated yet
    }
}

<|endoftext|>


<commit_before>use std::io;
use std::mem;
use std::os::windows::io::{RawHandle, AsRawHandle};

use winapi::{HANDLE, STD_OUTPUT_HANDLE,
             CONSOLE_SCREEN_BUFFER_INFO, COORD};
use kernel32::{GetStdHandle, GetConsoleScreenBufferInfo,
               GetConsoleMode, SetConsoleCursorPosition};

use term::Term;

pub const DEFAULT_WIDTH: u16 = 79;

pub fn is_a_terminal() -> bool {
    unsafe {
        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
        let mut out = 0;
        GetConsoleMode(handle, &mut out) != 0
    }
}

pub fn terminal_size() -> Option<(u16, u16)> {
    let hand = STD_OUTPUT_HANDLE as RawHandle;
    if let Some((_, csbi)) = get_console_screen_buffer_info(hand) {
        Some(((csbi.srWindow.Right - csbi.srWindow.Left) as u16,
              (csbi.srWindow.Bottom - csbi.srWindow.Top) as u16))
    } else {
        None
    }
}

pub fn move_cursor_up(out: &Term, n: usize) -> io::Result<()> {
    if let Some((hand, csbi)) = get_console_screen_buffer_info(out.as_raw_handle()) {
        unsafe {
            SetConsoleCursorPosition(hand, COORD {
                X: 0,
                Y: csbi.dwCursorPosition.Y - n as i16,
            });
        }
    }
    Ok(())
}

pub fn move_cursor_down(out: &Term, n: usize) -> io::Result<()> {
    if let Some((hand, csbi)) = get_console_screen_buffer_info(out.as_raw_handle()) {
        unsafe {
            SetConsoleCursorPosition(hand, COORD {
                X: 0,
                Y: csbi.dwCursorPosition.Y + n as i16,
            });
        }
    }
    Ok(())
}

pub fn clear_line(out: &Term) -> io::Result<()> {
    if let Some((_, csbi)) = get_console_screen_buffer_info(out.as_raw_handle()) {
        out.write_str(&format!("\r{0:width$}\r", "", width=
            (csbi.srWindow.Right - csbi.srWindow.Left) as usize))?;
    }
    Ok(())
}

fn get_console_screen_buffer_info(hand: HANDLE)
    -> Option<(HANDLE, CONSOLE_SCREEN_BUFFER_INFO)>
{
    let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = unsafe { mem::zeroed() };
    match unsafe { GetConsoleScreenBufferInfo(hand, &mut csbi) } {
        0 => None,
        _ => Some((hand, csbi)),
    }
}
<commit_msg>Correctly clear lines<commit_after>use std::io;
use std::mem;
use std::os::windows::io::{RawHandle, AsRawHandle};

use winapi::{WCHAR, HANDLE, STD_OUTPUT_HANDLE,
             CONSOLE_SCREEN_BUFFER_INFO, COORD};
use kernel32::{GetStdHandle, GetConsoleScreenBufferInfo,
               GetConsoleMode, SetConsoleCursorPosition,
               FillConsoleOutputCharacter};

use term::Term;

pub const DEFAULT_WIDTH: u16 = 79;

pub fn is_a_terminal() -> bool {
    unsafe {
        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
        let mut out = 0;
        GetConsoleMode(handle, &mut out) != 0
    }
}

pub fn terminal_size() -> Option<(u16, u16)> {
    let hand = STD_OUTPUT_HANDLE as RawHandle;
    if let Some((_, csbi)) = get_console_screen_buffer_info(hand) {
        Some(((csbi.srWindow.Right - csbi.srWindow.Left) as u16,
              (csbi.srWindow.Bottom - csbi.srWindow.Top) as u16))
    } else {
        None
    }
}

pub fn move_cursor_up(out: &Term, n: usize) -> io::Result<()> {
    if let Some((hand, csbi)) = get_console_screen_buffer_info(out.as_raw_handle()) {
        unsafe {
            SetConsoleCursorPosition(hand, COORD {
                X: 0,
                Y: csbi.dwCursorPosition.Y - n as i16,
            });
        }
    }
    Ok(())
}

pub fn move_cursor_down(out: &Term, n: usize) -> io::Result<()> {
    if let Some((hand, csbi)) = get_console_screen_buffer_info(out.as_raw_handle()) {
        unsafe {
            SetConsoleCursorPosition(hand, COORD {
                X: 0,
                Y: csbi.dwCursorPosition.Y + n as i16,
            });
        }
    }
    Ok(())
}

pub fn clear_line(out: &Term) -> io::Result<()> {
    if let Some((hand, csbi)) = get_console_screen_buffer_info(out.as_raw_handle()) {
        unsafe {
            let width = csbi.srWindow.Right - csbi.srWindow.Left;
            let pos = COORD {
                X: 0,
                Y: csbi.dwCursorPosition.Y,
            };
            let mut written;
            FillConsoleOutputCharacter(hand, b' ' as WCHAR,
                                       width, pos, &mut written);
        }
    }
    Ok(())
}

fn get_console_screen_buffer_info(hand: HANDLE)
    -> Option<(HANDLE, CONSOLE_SCREEN_BUFFER_INFO)>
{
    let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = unsafe { mem::zeroed() };
    match unsafe { GetConsoleScreenBufferInfo(hand, &mut csbi) } {
        0 => None,
        _ => Some((hand, csbi)),
    }
}
<|endoftext|>


<commit_before>#![cfg(test)]

use super::ast;
use super::grammar;
use super::runtime;

const SIMPLE_INIT: &'static str = r#"match (message init) { acknowledge init; }"#;
const TWO_MSGS: &'static str =
    r#"match (message foo, message bar) { acknowledge foo; acknowledge bar; }"#;
const SIMPLE_EQUAL: &'static str = r#"match (foo == bar) { unset foo; }"#;
const SIMPLE_NOT_EQUAL: &'static str = r#"match (foo != bar) { set foo bar; }"#;

fn parse_one_match(s: &str) -> ast::Match {
    let mut g = grammar::glop(s).unwrap();
    assert_eq!(g.matches.len(), 1);
    g.matches.pop().unwrap()
}

#[test]
fn unmatched_init_empty_state() {
    let m_ast = parse_one_match(SIMPLE_INIT);
    let mut st = runtime::State::new();
    let m_exc = runtime::Match::new_from_ast(&m_ast);
    match m_exc.eval(&mut st) {
        Some(_) => panic!("unexpected match"),
        None => (),
    }
}

#[test]
fn matched_init_message() {
    let m_ast = parse_one_match(SIMPLE_INIT);
    let mut st = runtime::State::new();
    st.push_msg("init", runtime::Msg::new());
    let m_exc = runtime::Match::new_from_ast(&m_ast);
    match m_exc.eval(&mut st) {
        Some(ctx) => {
            assert_eq!(ctx.seq, 1);
            assert!(ctx.msgs.contains_key("init"));
            assert_eq!(ctx.msgs.len(), 1);
        }
        None => panic!("expected match"),
    }
    // match m_exc.eval(&mut st) {
    // Some(_) => panic("unexpected match"),
    // None => {}
    // }
}

#[test]
fn matched_only_init_message() {
    let m_ast = parse_one_match(SIMPLE_INIT);
    let mut st = runtime::State::new();
    st.push_msg("init", runtime::Msg::new());
    st.push_msg("blah",
                [("foo".to_string(), "bar".to_string())].iter().cloned().collect());
    let m_exc = runtime::Match::new_from_ast(&m_ast);
    match m_exc.eval(&mut st) {
        Some(ctx) => {
            assert_eq!(ctx.seq, 1);
            assert!(ctx.msgs.contains_key("init"));
            assert_eq!(ctx.msgs.len(), 1);
        }
        None => panic!("expected match"),
    }
    // match m_exc.eval(&mut st) {
    // Some(_) => panic("unexpected match"),
    // None => {}
    // }
}

#[test]
fn matched_two_messages() {
    let m_ast = parse_one_match(TWO_MSGS);
    let mut st = runtime::State::new();
    st.push_msg("foo", runtime::Msg::new());
    st.push_msg("bar", runtime::Msg::new());
    let m_exc = runtime::Match::new_from_ast(&m_ast);
    match m_exc.eval(&mut st) {
        Some(ctx) => {
            assert_eq!(ctx.seq, 1);
            assert!(ctx.msgs.contains_key("foo"));
            assert!(ctx.msgs.contains_key("bar"));
            assert_eq!(ctx.msgs.len(), 2);
        }
        None => panic!("expected match"),
    }
    // match m_exc.eval(&mut st) {
    // Some(_) => panic("unexpected match"),
    // None => {}
    // }
}

#[test]
fn matched_equal() {
    let m_ast = parse_one_match(SIMPLE_EQUAL);
    {
        let mut st = runtime::State::new();
        st.set_var("foo", "bar");
        let m_exc = runtime::Match::new_from_ast(&m_ast);
        match m_exc.eval(&mut st) {
            Some(ctx) => {
                assert_eq!(ctx.seq, 1);
            }
            None => panic!("expected match"),
        }
    }
    {
        let mut st = runtime::State::new();
        st.set_var("foo", "blah");
        let m_exc = runtime::Match::new_from_ast(&m_ast);
        match m_exc.eval(&mut st) {
            Some(_) => panic!("unexpected match"),
            None => {}
        }
    }
}

#[test]
fn matched_not_equal() {
    let m_ast = parse_one_match(SIMPLE_NOT_EQUAL);
    {
        let mut st = runtime::State::new();
        st.set_var("foo", "blah");
        let m_exc = runtime::Match::new_from_ast(&m_ast);
        match m_exc.eval(&mut st) {
            Some(ctx) => {
                assert_eq!(ctx.seq, 1);
            }
            None => panic!("expected match"),
        }
    }
    {
        let mut st = runtime::State::new();
        st.set_var("foo", "bar");
        let m_exc = runtime::Match::new_from_ast(&m_ast);
        match m_exc.eval(&mut st) {
            Some(_) => panic!("unexpected match"),
            None => {}
        }
    }
}
<commit_msg>Add is_set test.<commit_after>#![cfg(test)]

use super::ast;
use super::grammar;
use super::runtime;

const SIMPLE_INIT: &'static str = r#"match (message init) { acknowledge init; }"#;
const TWO_MSGS: &'static str =
    r#"match (message foo, message bar) { acknowledge foo; acknowledge bar; }"#;
const SIMPLE_EQUAL: &'static str = r#"match (foo == bar) { unset foo; }"#;
const SIMPLE_NOT_EQUAL: &'static str = r#"match (foo != bar) { set foo bar; }"#;
const SIMPLE_IS_SET: &'static str = r#"match (is_set foo) { unset foo; }"#;

fn parse_one_match(s: &str) -> ast::Match {
    let mut g = grammar::glop(s).unwrap();
    assert_eq!(g.matches.len(), 1);
    g.matches.pop().unwrap()
}

#[test]
fn unmatched_init_empty_state() {
    let m_ast = parse_one_match(SIMPLE_INIT);
    let mut st = runtime::State::new();
    let m_exc = runtime::Match::new_from_ast(&m_ast);
    match m_exc.eval(&mut st) {
        Some(_) => panic!("unexpected match"),
        None => (),
    }
}

#[test]
fn matched_init_message() {
    let m_ast = parse_one_match(SIMPLE_INIT);
    let mut st = runtime::State::new();
    st.push_msg("init", runtime::Msg::new());
    let m_exc = runtime::Match::new_from_ast(&m_ast);
    match m_exc.eval(&mut st) {
        Some(ctx) => {
            assert_eq!(ctx.seq, 1);
            assert!(ctx.msgs.contains_key("init"));
            assert_eq!(ctx.msgs.len(), 1);
        }
        None => panic!("expected match"),
    }
    // match m_exc.eval(&mut st) {
    // Some(_) => panic("unexpected match"),
    // None => {}
    // }
}

#[test]
fn matched_only_init_message() {
    let m_ast = parse_one_match(SIMPLE_INIT);
    let mut st = runtime::State::new();
    st.push_msg("init", runtime::Msg::new());
    st.push_msg("blah",
                [("foo".to_string(), "bar".to_string())].iter().cloned().collect());
    let m_exc = runtime::Match::new_from_ast(&m_ast);
    match m_exc.eval(&mut st) {
        Some(ctx) => {
            assert_eq!(ctx.seq, 1);
            assert!(ctx.msgs.contains_key("init"));
            assert_eq!(ctx.msgs.len(), 1);
        }
        None => panic!("expected match"),
    }
    // match m_exc.eval(&mut st) {
    // Some(_) => panic("unexpected match"),
    // None => {}
    // }
}

#[test]
fn matched_two_messages() {
    let m_ast = parse_one_match(TWO_MSGS);
    let mut st = runtime::State::new();
    st.push_msg("foo", runtime::Msg::new());
    st.push_msg("bar", runtime::Msg::new());
    let m_exc = runtime::Match::new_from_ast(&m_ast);
    match m_exc.eval(&mut st) {
        Some(ctx) => {
            assert_eq!(ctx.seq, 1);
            assert!(ctx.msgs.contains_key("foo"));
            assert!(ctx.msgs.contains_key("bar"));
            assert_eq!(ctx.msgs.len(), 2);
        }
        None => panic!("expected match"),
    }
    // match m_exc.eval(&mut st) {
    // Some(_) => panic("unexpected match"),
    // None => {}
    // }
}

#[test]
fn match_equal() {
    let m_ast = parse_one_match(SIMPLE_EQUAL);
    {
        let mut st = runtime::State::new();
        st.set_var("foo", "bar");
        let m_exc = runtime::Match::new_from_ast(&m_ast);
        match m_exc.eval(&mut st) {
            Some(ctx) => {
                assert_eq!(ctx.seq, 1);
            }
            None => panic!("expected match"),
        }
    }
    {
        let mut st = runtime::State::new();
        st.set_var("foo", "blah");
        let m_exc = runtime::Match::new_from_ast(&m_ast);
        match m_exc.eval(&mut st) {
            Some(_) => panic!("unexpected match"),
            None => {}
        }
    }
}

#[test]
fn match_not_equal() {
    let m_ast = parse_one_match(SIMPLE_NOT_EQUAL);
    {
        let mut st = runtime::State::new();
        st.set_var("foo", "blah");
        let m_exc = runtime::Match::new_from_ast(&m_ast);
        match m_exc.eval(&mut st) {
            Some(ctx) => {
                assert_eq!(ctx.seq, 1);
            }
            None => panic!("expected match"),
        }
    }
    {
        let mut st = runtime::State::new();
        st.set_var("foo", "bar");
        let m_exc = runtime::Match::new_from_ast(&m_ast);
        match m_exc.eval(&mut st) {
            Some(_) => panic!("unexpected match"),
            None => {}
        }
    }
}

#[test]
fn match_is_set() {
    let m_ast = parse_one_match(SIMPLE_IS_SET);
    {
        let mut st = runtime::State::new();
        st.set_var("foo", "bar");
        let m_exc = runtime::Match::new_from_ast(&m_ast);
        match m_exc.eval(&mut st) {
            Some(ctx) => {
                assert_eq!(ctx.seq, 1);
            }
            None => panic!("expected match"),
        }
    }
    {
        let mut st = runtime::State::new();
        st.set_var("bar", "foo");
        let m_exc = runtime::Match::new_from_ast(&m_ast);
        match m_exc.eval(&mut st) {
            Some(_) => panic!("unexpected match"),
            None => {}
        }
    }
}
<|endoftext|>


<commit_before>use super::*;
use super::super::lexer;
use codemap::CodeMap;
use codemap::Spanned;
use std::fmt::Debug;
use std::cmp::PartialEq;

fn get_tokens(source: &str) -> Vec<Spanned<Token>> {
  let mut map = CodeMap::new();
  let file = map.add_file(String::from("_test"), String::from(source));
  lexer::lex(&file)
}

fn test_parse<T: Debug + PartialEq>(source: &str, func: &Fn(&mut ParseIter) -> T, expect: T) {
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(
    func(&mut it),
    expect
  );

  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::End))
  );
  it.next();

  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::EOF))
  );
  it.next();

  assert_eq!(parse_un_expr(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_quark() {
  test_parse("null", &parse_quark, Ok(Node::Null));
  test_parse("true", &parse_quark, Ok(Node::Bool(true)));
  test_parse("false", &parse_quark, Ok(Node::Bool(false)));
  test_parse("1.3", &parse_quark, Ok(Node::Float(1.3)));
  test_parse("0.3", &parse_quark, Ok(Node::Float(0.3)));
  test_parse("2", &parse_quark, Ok(Node::Int(2)));
  test_parse("3", &parse_quark, Ok(Node::Int(3)));
  test_parse("name", &parse_quark, Ok(Node::Name(String::from("name"))));
  test_parse("table", &parse_quark, Ok(Node::Table));
}

#[test]
fn test_atom() {
  test_parse(
    "null",
    &parse_atom,
    Ok(Node::Null)
    );

  test_parse(
    "(null)",
    &parse_atom,
    Ok(Node::Null)
    );
}

#[test]
fn test_simple() {
  test_parse(
    "foo",
    &parse_simple,
    Ok(Node::Name(String::from("foo")))
    );
  test_parse(
    "foo.bar",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Str(String::from("bar"))),
    })
  );
  test_parse(
    "foo[bar]",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Name(String::from("bar"))),
    })
  );
  test_parse(
    "foo()",
    &parse_simple,
    Ok(Node::Func {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    })
  );
  test_parse(
    "foo:bar()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Name(String::from("foo"))),
      method: Box::new(Node::Str(String::from("bar"))),
      args: Vec::new(),
    })
  );
  test_parse(
    "foo.bar()",
    &parse_simple,
    Ok(Node::Func {
      func: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
      args: Vec::new(),
    })
  );
  test_parse(
    "foo.bar[baz]:qux()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Index {
        lhs: Box::new(Node::Index {
          lhs: Box::new(Node::Name(String::from("foo"))),
          rhs: Box::new(Node::Str(String::from("bar"))),
        }),
        rhs: Box::new(Node::Name(String::from("baz"))),
      }),
      method: Box::new(Node::Str(String::from("qux"))),
      args: Vec::new(),
    })
  );
}

#[test]
fn test_fn_args() {
  test_parse(
    "()",
    &parse_fn_args,
    Ok(Vec::new())
  );
}

#[test]
fn test_un_expr() {
  test_parse(
    "5",
    &parse_un_expr,
    Ok(Node::Int(5))
  );

  test_parse(
    "foo()",
    &parse_un_expr,
    Ok(Node::Func {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    })
  );

  test_parse(
    "-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Int(5)),
    })
  );

  test_parse(
    "-foo.bar",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
    })
  );

  test_parse(
    "!-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Not,
      val: Box::new(Node::UnExpr {
        op: lexer::Token::Sub,
        val: Box::new(Node::Int(5)),
      }),
    })
  );
}

#[test]
fn test_bin_expr() {
  test_parse(
    "1 + 2",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    })
  );

  test_parse(
    "(1 + 2)",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    })
  );

  test_parse(
    "1 + 2 * 3",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::BinExpr {
        lhs: Box::new(Node::Int(2)),
        op: lexer::Token::Mul,
        rhs: Box::new(Node::Int(3)),
      }),
    })
  );
}

#[test]
fn test_fn_expr() {
  test_parse(
    "|| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: Vec::new(),
      expr: Box::new(Node::Int(5)),
    })
  );

  test_parse(
    "|x| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    })
  );

  test_parse(
    "|x,| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    })
  );

  test_parse(
    "|x,y| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x"), String::from("y")],
      expr: Box::new(Node::Int(5)),
    })
  );
}
<commit_msg>rustfmt<commit_after>use super::*;
use super::super::lexer;
use codemap::CodeMap;
use codemap::Spanned;
use std::fmt::Debug;
use std::cmp::PartialEq;

fn get_tokens(source: &str) -> Vec<Spanned<Token>> {
  let mut map = CodeMap::new();
  let file = map.add_file(String::from("_test"), String::from(source));
  lexer::lex(&file)
}

fn test_parse<T: Debug + PartialEq>(source: &str, func: &Fn(&mut ParseIter) -> T, expect: T) {
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(func(&mut it), expect);

  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::End))
  );
  it.next();

  assert_eq!(
    parse_un_expr(&mut it),
    Err(UnexpectedToken(lexer::Token::EOF))
  );
  it.next();

  assert_eq!(parse_un_expr(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_quark() {
  test_parse("null", &parse_quark, Ok(Node::Null));
  test_parse("true", &parse_quark, Ok(Node::Bool(true)));
  test_parse("false", &parse_quark, Ok(Node::Bool(false)));
  test_parse("1.3", &parse_quark, Ok(Node::Float(1.3)));
  test_parse("0.3", &parse_quark, Ok(Node::Float(0.3)));
  test_parse("2", &parse_quark, Ok(Node::Int(2)));
  test_parse("3", &parse_quark, Ok(Node::Int(3)));
  test_parse("name", &parse_quark, Ok(Node::Name(String::from("name"))));
  test_parse("table", &parse_quark, Ok(Node::Table));
}

#[test]
fn test_atom() {
  test_parse("null", &parse_atom, Ok(Node::Null));

  test_parse("(null)", &parse_atom, Ok(Node::Null));
}

#[test]
fn test_simple() {
  test_parse("foo", &parse_simple, Ok(Node::Name(String::from("foo"))));
  test_parse(
    "foo.bar",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Str(String::from("bar"))),
    }),
  );
  test_parse(
    "foo[bar]",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Name(String::from("bar"))),
    }),
  );
  test_parse(
    "foo()",
    &parse_simple,
    Ok(Node::Func {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo:bar()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Name(String::from("foo"))),
      method: Box::new(Node::Str(String::from("bar"))),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo.bar()",
    &parse_simple,
    Ok(Node::Func {
      func: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo.bar[baz]:qux()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Index {
        lhs: Box::new(Node::Index {
          lhs: Box::new(Node::Name(String::from("foo"))),
          rhs: Box::new(Node::Str(String::from("bar"))),
        }),
        rhs: Box::new(Node::Name(String::from("baz"))),
      }),
      method: Box::new(Node::Str(String::from("qux"))),
      args: Vec::new(),
    }),
  );
}

#[test]
fn test_fn_args() {
  test_parse("()", &parse_fn_args, Ok(Vec::new()));
}

#[test]
fn test_un_expr() {
  test_parse("5", &parse_un_expr, Ok(Node::Int(5)));

  test_parse(
    "foo()",
    &parse_un_expr,
    Ok(Node::Func {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    }),
  );

  test_parse(
    "-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "-foo.bar",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
    }),
  );

  test_parse(
    "!-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Not,
      val: Box::new(Node::UnExpr {
        op: lexer::Token::Sub,
        val: Box::new(Node::Int(5)),
      }),
    }),
  );
}

#[test]
fn test_bin_expr() {
  test_parse(
    "1 + 2",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    }),
  );

  test_parse(
    "(1 + 2)",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    }),
  );

  test_parse(
    "1 + 2 * 3",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::BinExpr {
        lhs: Box::new(Node::Int(2)),
        op: lexer::Token::Mul,
        rhs: Box::new(Node::Int(3)),
      }),
    }),
  );
}

#[test]
fn test_fn_expr() {
  test_parse(
    "|| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: Vec::new(),
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x,| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x,y| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x"), String::from("y")],
      expr: Box::new(Node::Int(5)),
    }),
  );
}
<|endoftext|>


<commit_before>extern crate kafka;
extern crate getopts;

use std::{env, fmt, process};
use std::fs::File;
use std::io::{self, stdin, stderr, Write, BufRead, BufReader};

use kafka::client::{KafkaClient, Compression};
use kafka::producer::{Producer, Record};

// how many brokers do we require to acknowledge the send messages
const REQUIRED_ACKS: i16 = 1;
// how long do we allow wainting for the acknowledgement
const ACK_TIMEOUT: i32 = 100;

/// This is a very simple command line application sending every
/// non-empty line of standard input to a specified kafka topic; one
/// by one (not the most efficient way, of course).
///
/// Alternatively, messages can be read from an input file and sent do
/// kafka in batches (the typical use-case).
fn main() {
    let cfg = match Config::from_cmdline() {
        Ok(cfg) => cfg,
        Err(e) => {
            println!("{}", e);
            process::exit(1);
        }
    };
    if let Err(e) = produce(&cfg) {
        println!("{}", e);
        process::exit(1);
    }
}

fn produce(cfg: &Config) -> Result<(), Error> {
    let mut client = KafkaClient::new(cfg.brokers.clone());
    client.set_compression(cfg.compression);
    try!(client.load_metadata_all());

    // ~ verify that the remote brokers do know about the target topic
    if !client.topics().contains(&cfg.topic) {
        return Err(Error::Literal(format!("No such topic at {:?}: {}", cfg.brokers, cfg.topic)));
    }
    match cfg.input_file {
        None => {
            let stdin = stdin();
            let mut stdin = stdin.lock();
            produce_impl(&mut stdin, client, &cfg)
        }
        Some(ref file) => {
            let mut r = BufReader::new(try!(File::open(file)));
            produce_impl(&mut r, client, &cfg)
        }
    }
}

fn produce_impl(src: &mut BufRead, client: KafkaClient, cfg: &Config) -> Result<(), Error> {
    let mut producer = try!(Producer::from_client(client)
                            .with_ack_timeout(ACK_TIMEOUT)
                            .with_required_acks(REQUIRED_ACKS)
                            .create());
    if cfg.batch_size < 2 {
        produce_impl_nobatch(&mut producer, src, cfg)
    } else {
        produce_impl_inbatches(&mut producer, src, cfg)
    }
}

fn produce_impl_nobatch(producer: &mut Producer, src: &mut BufRead, cfg: &Config) -> Result<(), Error> {
    let mut stderr = stderr();
    let mut rec = Record::from_value(&cfg.topic, String::new());
    loop {
        rec.value.clear();
        if try!(src.read_line(&mut rec.value)) == 0 {
            break; // ~ EOF reached
        }
        if rec.value.trim().is_empty() {
            continue; // ~ skip empty lines
        }
        // ~ directly send to kafka
        let r = try!(producer.send(&rec));
        let _ = write!(stderr, "debug: {:?}\n", r);
    }
    Ok(())
}

// This implementation wants to be efficient.  It buffers N lines from
// the source and sends these in batches to Kafka.  Line buffers
// across batches are re-used for the sake of avoiding allocations.
fn produce_impl_inbatches(producer: &mut Producer, src: &mut BufRead, cfg: &Config)
                          -> Result<(), Error>
{
    assert!(cfg.batch_size > 1);

    // ~ a buffer of prepared records to be send in a batch to Kafka
    // ~ in the loop following, we'll only modify the 'value' of the
    // cached records
    let mut rec_stash: Vec<Record<(), String>> =
        (0 .. cfg.batch_size)
        .map(|_| Record::from_value(&cfg.topic, String::new()))
        .collect();
    // ~ points to the next free slot in `rec_stash`.  if it reaches
    // `rec_stash.len()` we'll send `rec_stash` to kafka
    let mut next_rec = 0;
    loop {
        // ~ send out a batch if it's ready
        if next_rec == rec_stash.len() {
            try!(send_batch(producer, &rec_stash));
            next_rec = 0;
        }
        let mut rec = &mut rec_stash[next_rec];
        if try!(src.read_line(&mut rec.value)) == 0 {
            break; // ~ EOF reached
        }
        if rec.value.trim().is_empty() {
            continue; // ~ skip empty lines
        }
        // ~ ok, we got a line. read the next one in a new buffer
        next_rec += 1;
    }
    // ~ flush pending messages - if any
    if next_rec > 0 {
        try!(send_batch(producer, &rec_stash[..next_rec]));
    }
    Ok(())
}

fn send_batch(producer: &mut Producer, batch: &[Record<(), String>]) -> Result<(), Error> {
    let rs = try!(producer.send_all(batch));
    for r in rs {
        if let Err(e) = r.offset {
            return Err(From::from(e));
        }
    }
    Ok(())
}

// --------------------------------------------------------------------

enum Error {
    Kafka(kafka::error::Error),
    Io(io::Error),
    Literal(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::Kafka(ref e) => write!(f, "kafka-error: {}", e),
            &Error::Io(ref e) => write!(f, "io-error: {}", e),
            &Error::Literal(ref s) => write!(f, "{}", s),
        }
    }
}

impl From<kafka::error::Error> for Error {
    fn from(e: kafka::error::Error) -> Self { Error::Kafka(e) }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self { Error::Io(e) }
}

// --------------------------------------------------------------------

struct Config {
    brokers: Vec<String>,
    topic: String,
    input_file: Option<String>,
    compression: Compression,
    batch_size: usize,
}

impl Config {
    fn from_cmdline() -> Result<Config, Error> {
        let args: Vec<String> = env::args().collect();
        let mut opts = getopts::Options::new();
        opts.optflag("h", "help", "Print this help screen");
        opts.optopt("", "brokers", "Specify kafka brokers (comma separated)", "HOSTS");
        opts.optopt("", "topic", "Specify target topic", "NAME");
        opts.optopt("", "input", "Specify input file", "FILE");
        opts.optopt("", "compression", "Compress messages [NONE, GZIP, SNAPPY]", "TYPE");
        opts.optopt("", "batch-size", "Send N message in one batch.", "N");

        let m = match opts.parse(&args[1..]) {
            Ok(m) => m,
            Err(e) => return Err(Error::Literal(e.to_string())),
        };
        if m.opt_present("help") {
            let brief = format!("{} [options]", args[0]);
            return Err(Error::Literal(opts.usage(&brief)));
        }
        Ok(Config {
            brokers: m.opt_str("brokers")
                .unwrap_or_else(|| "localhost:9092".to_owned())
                .split(',')
                .map(|s| s.trim().to_owned())
                .collect(),
            topic: m.opt_str("topic")
                .unwrap_or_else(|| "my-topic".to_owned()),
            input_file: m.opt_str("input"),
            compression: {
                let s = m.opt_str("compression")
                    .unwrap_or_else(|| "NONE".to_owned());
                match s.trim() {
                    "none" | "NONE" => Compression::NONE,
                    "gzip" | "GZIP" => Compression::GZIP,
                    "snappy" | "SNAPPY" => Compression::SNAPPY,
                    _ => return Err(Error::Literal(format!("Unknown compression type: {}", s))),
                }
            },
            batch_size: {
                match m.opt_str("batch-size") {
                    None => 1,
                    Some(s) => {
                        match s.parse::<usize>() {
                            Ok(n) => n,
                            Err(_) => return Err(Error::Literal(format!("Not a number: {}", s))),
                        }
                    }
                }
            },
        })
    }
}
<commit_msg>#! console-producer: fix sending lines in batch mode<commit_after>extern crate kafka;
extern crate getopts;

use std::{env, fmt, process};
use std::fs::File;
use std::io::{self, stdin, stderr, Write, BufRead, BufReader};

use kafka::client::{KafkaClient, Compression};
use kafka::producer::{Producer, Record};

// how many brokers do we require to acknowledge the send messages
const REQUIRED_ACKS: i16 = 1;
// how long do we allow wainting for the acknowledgement
const ACK_TIMEOUT: i32 = 100;

/// This is a very simple command line application sending every
/// non-empty line of standard input to a specified kafka topic; one
/// by one (not the most efficient way, of course).
///
/// Alternatively, messages can be read from an input file and sent do
/// kafka in batches (the typical use-case).
fn main() {
    let cfg = match Config::from_cmdline() {
        Ok(cfg) => cfg,
        Err(e) => {
            println!("{}", e);
            process::exit(1);
        }
    };
    if let Err(e) = produce(&cfg) {
        println!("{}", e);
        process::exit(1);
    }
}

fn produce(cfg: &Config) -> Result<(), Error> {
    let mut client = KafkaClient::new(cfg.brokers.clone());
    client.set_compression(cfg.compression);
    try!(client.load_metadata_all());

    // ~ verify that the remote brokers do know about the target topic
    if !client.topics().contains(&cfg.topic) {
        return Err(Error::Literal(format!("No such topic at {:?}: {}", cfg.brokers, cfg.topic)));
    }
    match cfg.input_file {
        None => {
            let stdin = stdin();
            let mut stdin = stdin.lock();
            produce_impl(&mut stdin, client, &cfg)
        }
        Some(ref file) => {
            let mut r = BufReader::new(try!(File::open(file)));
            produce_impl(&mut r, client, &cfg)
        }
    }
}

fn produce_impl(src: &mut BufRead, client: KafkaClient, cfg: &Config) -> Result<(), Error> {
    let mut producer = try!(Producer::from_client(client)
                            .with_ack_timeout(ACK_TIMEOUT)
                            .with_required_acks(REQUIRED_ACKS)
                            .create());
    if cfg.batch_size < 2 {
        produce_impl_nobatch(&mut producer, src, cfg)
    } else {
        produce_impl_inbatches(&mut producer, src, cfg)
    }
}

fn produce_impl_nobatch(producer: &mut Producer, src: &mut BufRead, cfg: &Config) -> Result<(), Error> {
    let mut stderr = stderr();
    let mut rec = Record::from_value(&cfg.topic, String::new());
    loop {
        rec.value.clear();
        if try!(src.read_line(&mut rec.value)) == 0 {
            break; // ~ EOF reached
        }
        if rec.value.trim().is_empty() {
            continue; // ~ skip empty lines
        }
        // ~ directly send to kafka
        let r = try!(producer.send(&rec));
        let _ = write!(stderr, "debug: {:?}\n", r);
    }
    Ok(())
}

// This implementation wants to be efficient.  It buffers N lines from
// the source and sends these in batches to Kafka.  Line buffers
// across batches are re-used for the sake of avoiding allocations.
fn produce_impl_inbatches(producer: &mut Producer, src: &mut BufRead, cfg: &Config)
                          -> Result<(), Error>
{
    assert!(cfg.batch_size > 1);

    // ~ a buffer of prepared records to be send in a batch to Kafka
    // ~ in the loop following, we'll only modify the 'value' of the
    // cached records
    let mut rec_stash: Vec<Record<(), String>> =
        (0 .. cfg.batch_size)
        .map(|_| Record::from_value(&cfg.topic, String::new()))
        .collect();
    // ~ points to the next free slot in `rec_stash`.  if it reaches
    // `rec_stash.len()` we'll send `rec_stash` to kafka
    let mut next_rec = 0;
    loop {
        // ~ send out a batch if it's ready
        if next_rec == rec_stash.len() {
            try!(send_batch(producer, &rec_stash));
            next_rec = 0;
        }
        let mut rec = &mut rec_stash[next_rec];
        rec.value.clear();
        if try!(src.read_line(&mut rec.value)) == 0 {
            break; // ~ EOF reached
        }
        if rec.value.trim().is_empty() {
            continue; // ~ skip empty lines
        }
        // ~ ok, we got a line. read the next one in a new buffer
        next_rec += 1;
    }
    // ~ flush pending messages - if any
    if next_rec > 0 {
        try!(send_batch(producer, &rec_stash[..next_rec]));
    }
    Ok(())
}

fn send_batch(producer: &mut Producer, batch: &[Record<(), String>]) -> Result<(), Error> {
    let rs = try!(producer.send_all(batch));
    for r in rs {
        if let Err(e) = r.offset {
            return Err(From::from(e));
        }
    }
    Ok(())
}

// --------------------------------------------------------------------

enum Error {
    Kafka(kafka::error::Error),
    Io(io::Error),
    Literal(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::Kafka(ref e) => write!(f, "kafka-error: {}", e),
            &Error::Io(ref e) => write!(f, "io-error: {}", e),
            &Error::Literal(ref s) => write!(f, "{}", s),
        }
    }
}

impl From<kafka::error::Error> for Error {
    fn from(e: kafka::error::Error) -> Self { Error::Kafka(e) }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self { Error::Io(e) }
}

// --------------------------------------------------------------------

struct Config {
    brokers: Vec<String>,
    topic: String,
    input_file: Option<String>,
    compression: Compression,
    batch_size: usize,
}

impl Config {
    fn from_cmdline() -> Result<Config, Error> {
        let args: Vec<String> = env::args().collect();
        let mut opts = getopts::Options::new();
        opts.optflag("h", "help", "Print this help screen");
        opts.optopt("", "brokers", "Specify kafka brokers (comma separated)", "HOSTS");
        opts.optopt("", "topic", "Specify target topic", "NAME");
        opts.optopt("", "input", "Specify input file", "FILE");
        opts.optopt("", "compression", "Compress messages [NONE, GZIP, SNAPPY]", "TYPE");
        opts.optopt("", "batch-size", "Send N message in one batch.", "N");

        let m = match opts.parse(&args[1..]) {
            Ok(m) => m,
            Err(e) => return Err(Error::Literal(e.to_string())),
        };
        if m.opt_present("help") {
            let brief = format!("{} [options]", args[0]);
            return Err(Error::Literal(opts.usage(&brief)));
        }
        Ok(Config {
            brokers: m.opt_str("brokers")
                .unwrap_or_else(|| "localhost:9092".to_owned())
                .split(',')
                .map(|s| s.trim().to_owned())
                .collect(),
            topic: m.opt_str("topic")
                .unwrap_or_else(|| "my-topic".to_owned()),
            input_file: m.opt_str("input"),
            compression: {
                let s = m.opt_str("compression")
                    .unwrap_or_else(|| "NONE".to_owned());
                match s.trim() {
                    "none" | "NONE" => Compression::NONE,
                    "gzip" | "GZIP" => Compression::GZIP,
                    "snappy" | "SNAPPY" => Compression::SNAPPY,
                    _ => return Err(Error::Literal(format!("Unknown compression type: {}", s))),
                }
            },
            batch_size: {
                match m.opt_str("batch-size") {
                    None => 1,
                    Some(s) => {
                        match s.parse::<usize>() {
                            Ok(n) => n,
                            Err(_) => return Err(Error::Literal(format!("Not a number: {}", s))),
                        }
                    }
                }
            },
        })
    }
}
<|endoftext|>


<commit_before><commit_msg>Update context_switches.rs<commit_after><|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{account_address::AccountAddress, account_config::constants::ACCOUNT_MODULE_NAME};
use move_core_types::move_resource::MoveResource;
#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct KeyRotationCapabilityResource {
    account_address: AccountAddress,
}

impl KeyRotationCapabilityResource {
    pub fn account_address(&self) -> &AccountAddress {
        &self.account_address
    }
}

impl MoveResource for KeyRotationCapabilityResource {
    const MODULE_NAME: &'static str = ACCOUNT_MODULE_NAME;
    const STRUCT_NAME: &'static str = "KeyRotationCapability";
}
<commit_msg>Removing account_address from types/src/account_config/resources/key_rotation_capability.rs<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{account_address::AccountAddress, account_config::constants::ACCOUNT_MODULE_NAME};
use move_core_types::move_resource::MoveResource;
#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct KeyRotationCapabilityResource {
    account_address: AccountAddress,
}

impl KeyRotationCapabilityResource {}

impl MoveResource for KeyRotationCapabilityResource {
    const MODULE_NAME: &'static str = ACCOUNT_MODULE_NAME;
    const STRUCT_NAME: &'static str = "KeyRotationCapability";
}
<|endoftext|>