<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.

//! A process-wide libuv event loop for library use.

#[forbid(deprecated_mode)];

use ll = uv_ll;
use iotask = uv_iotask;
use get_gl = get;
use uv_iotask::{IoTask, spawn_iotask};

use core::either::{Left, Right};
use core::libc;
use core::pipes::{Port, Chan, SharedChan, select2i};
use core::private::global::{global_data_clone_create,
                            global_data_clone};
use core::private::weak_task::weaken_task;
use core::str;
use core::task::{task, SingleThreaded, spawn};
use core::task;
use core::vec;
use core::clone::Clone;
use core::option::{Some, None};

/**
 * Race-free helper to get access to a global task where a libuv
 * loop is running.
 *
 * Use `uv::hl::interact` to do operations against the global
 * loop that this function returns.
 *
 * # Return
 *
 * * A `hl::high_level_loop` that encapsulates communication with the global
 * loop.
 */
pub fn get() -> IoTask {
    return get_monitor_task_gl();
}

#[doc(hidden)]
fn get_monitor_task_gl() -> IoTask unsafe {

    type MonChan = Chan<IoTask>;

    struct GlobalIoTask(IoTask);

    impl GlobalIoTask: Clone {
        fn clone(&self) -> GlobalIoTask {
            GlobalIoTask((**self).clone())
        }
    }

    fn key(_: GlobalIoTask) { }

    match global_data_clone(key) {
        Some(GlobalIoTask(iotask)) => iotask,
        None => {
            let iotask: IoTask = spawn_loop();
            let mut installed = false;
            let final_iotask = do global_data_clone_create(key) {
                installed = true;
                ~GlobalIoTask(iotask.clone())
            };
            if installed {
                do task().unlinked().spawn() unsafe {
                    debug!("global monitor task starting");
                    // As a weak task the runtime will notify us when to exit
                    do weaken_task |weak_exit_po| {
                        debug!("global monitor task is weak");
                        weak_exit_po.recv();
                        iotask::exit(&iotask);
                        debug!("global monitor task is unweak");
                    };
                    debug!("global monitor task exiting");
                }
            } else {
                iotask::exit(&iotask);
            }

            match final_iotask {
                GlobalIoTask(iotask) => iotask
            }
        }
    }
}

fn spawn_loop() -> IoTask {
    let builder = do task().add_wrapper |task_body| {
        fn~(move task_body) {
            // The I/O loop task also needs to be weak so it doesn't keep
            // the runtime alive
            unsafe {
                do weaken_task |_| {
                    debug!("global libuv task is now weak");
                    task_body();

                    // We don't wait for the exit message on weak_exit_po
                    // because the monitor task will tell the uv loop when to
                    // exit

                    debug!("global libuv task is leaving weakened state");
                }
            }
        }
    };
    let builder = builder.unlinked();
    spawn_iotask(move builder)
}

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

    use uv::iotask;
    use uv::ll;
    use uv_global_loop::*;

    use core::iter;
    use core::libc;
    use core::oldcomm;
    use core::ptr;
    use core::task;

    extern fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) unsafe {
        let exit_ch_ptr = ll::get_data_for_uv_handle(
            timer_ptr as *libc::c_void) as *oldcomm::Chan<bool>;
        let exit_ch = *exit_ch_ptr;
        oldcomm::send(exit_ch, true);
        log(debug, fmt!("EXIT_CH_PTR simple_timer_close_cb exit_ch_ptr: %?",
                       exit_ch_ptr));
    }
    extern fn simple_timer_cb(timer_ptr: *ll::uv_timer_t,
                             _status: libc::c_int) unsafe {
        log(debug, ~"in simple timer cb");
        ll::timer_stop(timer_ptr);
        let hl_loop = &get_gl();
        do iotask::interact(hl_loop) |_loop_ptr| unsafe {
            log(debug, ~"closing timer");
            ll::close(timer_ptr, simple_timer_close_cb);
            log(debug, ~"about to deref exit_ch_ptr");
            log(debug, ~"after msg sent on deref'd exit_ch");
        };
        log(debug, ~"exiting simple timer cb");
    }

    fn impl_uv_hl_simple_timer(iotask: &IoTask) unsafe {
        let exit_po = oldcomm::Port::<bool>();
        let exit_ch = oldcomm::Chan(&exit_po);
        let exit_ch_ptr = ptr::addr_of(&exit_ch);
        log(debug, fmt!("EXIT_CH_PTR newly created exit_ch_ptr: %?",
                       exit_ch_ptr));
        let timer_handle = ll::timer_t();
        let timer_ptr = ptr::addr_of(&timer_handle);
        do iotask::interact(iotask) |loop_ptr| unsafe {
            log(debug, ~"user code inside interact loop!!!");
            let init_status = ll::timer_init(loop_ptr, timer_ptr);
            if(init_status == 0i32) {
                ll::set_data_for_uv_handle(
                    timer_ptr as *libc::c_void,
                    exit_ch_ptr as *libc::c_void);
                let start_status = ll::timer_start(timer_ptr, simple_timer_cb,
                                                   1u, 0u);
                if(start_status == 0i32) {
                }
                else {
                    fail ~"failure on ll::timer_start()";
                }
            }
            else {
                fail ~"failure on ll::timer_init()";
            }
        };
        oldcomm::recv(exit_po);
        log(debug, ~"global_loop timer test: msg recv on exit_po, done..");
    }

    #[test]
    fn test_gl_uv_global_loop_high_level_global_timer() unsafe {
        let hl_loop = &get_gl();
        let exit_po = oldcomm::Port::<()>();
        let exit_ch = oldcomm::Chan(&exit_po);
        task::spawn_sched(task::ManualThreads(1u), || {
            let hl_loop = &get_gl();
            impl_uv_hl_simple_timer(hl_loop);
            oldcomm::send(exit_ch, ());
        });
        impl_uv_hl_simple_timer(hl_loop);
        oldcomm::recv(exit_po);
    }

    // keeping this test ignored until some kind of stress-test-harness
    // is set up for the build bots
    #[test]
    #[ignore]
    fn test_stress_gl_uv_global_loop_high_level_global_timer() unsafe {
        let exit_po = oldcomm::Port::<()>();
        let exit_ch = oldcomm::Chan(&exit_po);
        let cycles = 5000u;
        for iter::repeat(cycles) {
            task::spawn_sched(task::ManualThreads(1u), || {
                let hl_loop = &get_gl();
                impl_uv_hl_simple_timer(hl_loop);
                oldcomm::send(exit_ch, ());
            });
        };
        for iter::repeat(cycles) {
            oldcomm::recv(exit_po);
        };
        log(debug, ~"test_stress_gl_uv_global_loop_high_level_global_timer"+
            ~" exiting sucessfully!");
    }
}
<commit_msg>Stop using oldcomm in uv_global_loop tests<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.

//! A process-wide libuv event loop for library use.

#[forbid(deprecated_mode)];

use ll = uv_ll;
use iotask = uv_iotask;
use get_gl = get;
use uv_iotask::{IoTask, spawn_iotask};

use core::either::{Left, Right};
use core::libc;
use core::pipes::{Port, Chan, SharedChan, select2i};
use core::private::global::{global_data_clone_create,
                            global_data_clone};
use core::private::weak_task::weaken_task;
use core::str;
use core::task::{task, SingleThreaded, spawn};
use core::task;
use core::vec;
use core::clone::Clone;
use core::option::{Some, None};

/**
 * Race-free helper to get access to a global task where a libuv
 * loop is running.
 *
 * Use `uv::hl::interact` to do operations against the global
 * loop that this function returns.
 *
 * # Return
 *
 * * A `hl::high_level_loop` that encapsulates communication with the global
 * loop.
 */
pub fn get() -> IoTask {
    return get_monitor_task_gl();
}

#[doc(hidden)]
fn get_monitor_task_gl() -> IoTask unsafe {

    type MonChan = Chan<IoTask>;

    struct GlobalIoTask(IoTask);

    impl GlobalIoTask: Clone {
        fn clone(&self) -> GlobalIoTask {
            GlobalIoTask((**self).clone())
        }
    }

    fn key(_: GlobalIoTask) { }

    match global_data_clone(key) {
        Some(GlobalIoTask(iotask)) => iotask,
        None => {
            let iotask: IoTask = spawn_loop();
            let mut installed = false;
            let final_iotask = do global_data_clone_create(key) {
                installed = true;
                ~GlobalIoTask(iotask.clone())
            };
            if installed {
                do task().unlinked().spawn() unsafe {
                    debug!("global monitor task starting");
                    // As a weak task the runtime will notify us when to exit
                    do weaken_task |weak_exit_po| {
                        debug!("global monitor task is weak");
                        weak_exit_po.recv();
                        iotask::exit(&iotask);
                        debug!("global monitor task is unweak");
                    };
                    debug!("global monitor task exiting");
                }
            } else {
                iotask::exit(&iotask);
            }

            match final_iotask {
                GlobalIoTask(iotask) => iotask
            }
        }
    }
}

fn spawn_loop() -> IoTask {
    let builder = do task().add_wrapper |task_body| {
        fn~(move task_body) {
            // The I/O loop task also needs to be weak so it doesn't keep
            // the runtime alive
            unsafe {
                do weaken_task |_| {
                    debug!("global libuv task is now weak");
                    task_body();

                    // We don't wait for the exit message on weak_exit_po
                    // because the monitor task will tell the uv loop when to
                    // exit

                    debug!("global libuv task is leaving weakened state");
                }
            }
        }
    };
    let builder = builder.unlinked();
    spawn_iotask(move builder)
}

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

    use uv::iotask;
    use uv::ll;
    use uv_global_loop::*;

    use core::iter;
    use core::libc;
    use core::ptr;
    use core::task;
    use core::cast::transmute;
    use core::libc::c_void;
    use core::pipes::{stream, SharedChan, Chan};

    extern fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) unsafe {
        let exit_ch_ptr = ll::get_data_for_uv_handle(
            timer_ptr as *libc::c_void);
        let exit_ch = transmute::<*c_void, ~Chan<bool>>(exit_ch_ptr);
        exit_ch.send(true);
        log(debug, fmt!("EXIT_CH_PTR simple_timer_close_cb exit_ch_ptr: %?",
                       exit_ch_ptr));
    }
    extern fn simple_timer_cb(timer_ptr: *ll::uv_timer_t,
                             _status: libc::c_int) unsafe {
        log(debug, ~"in simple timer cb");
        ll::timer_stop(timer_ptr);
        let hl_loop = &get_gl();
        do iotask::interact(hl_loop) |_loop_ptr| unsafe {
            log(debug, ~"closing timer");
            ll::close(timer_ptr, simple_timer_close_cb);
            log(debug, ~"about to deref exit_ch_ptr");
            log(debug, ~"after msg sent on deref'd exit_ch");
        };
        log(debug, ~"exiting simple timer cb");
    }

    fn impl_uv_hl_simple_timer(iotask: &IoTask) unsafe {
        let (exit_po, exit_ch) = stream::<bool>();
        let exit_ch_ptr: *libc::c_void = transmute(~exit_ch);
        log(debug, fmt!("EXIT_CH_PTR newly created exit_ch_ptr: %?",
                       exit_ch_ptr));
        let timer_handle = ll::timer_t();
        let timer_ptr = ptr::addr_of(&timer_handle);
        do iotask::interact(iotask) |loop_ptr| unsafe {
            log(debug, ~"user code inside interact loop!!!");
            let init_status = ll::timer_init(loop_ptr, timer_ptr);
            if(init_status == 0i32) {
                ll::set_data_for_uv_handle(
                    timer_ptr as *libc::c_void,
                    exit_ch_ptr);
                let start_status = ll::timer_start(timer_ptr, simple_timer_cb,
                                                   1u, 0u);
                if(start_status == 0i32) {
                }
                else {
                    fail ~"failure on ll::timer_start()";
                }
            }
            else {
                fail ~"failure on ll::timer_init()";
            }
        };
        exit_po.recv();
        log(debug, ~"global_loop timer test: msg recv on exit_po, done..");
    }

    #[test]
    fn test_gl_uv_global_loop_high_level_global_timer() unsafe {
        let hl_loop = &get_gl();
        let (exit_po, exit_ch) = stream::<()>();
        task::spawn_sched(task::ManualThreads(1u), || {
            let hl_loop = &get_gl();
            impl_uv_hl_simple_timer(hl_loop);
            exit_ch.send(());
        });
        impl_uv_hl_simple_timer(hl_loop);
        exit_po.recv();
    }

    // keeping this test ignored until some kind of stress-test-harness
    // is set up for the build bots
    #[test]
    #[ignore]
    fn test_stress_gl_uv_global_loop_high_level_global_timer() unsafe {
        let (exit_po, exit_ch) = stream::<()>();
        let exit_ch = SharedChan(exit_ch);
        let cycles = 5000u;
        for iter::repeat(cycles) {
            let exit_ch_clone = exit_ch.clone();
            task::spawn_sched(task::ManualThreads(1u), || {
                let hl_loop = &get_gl();
                impl_uv_hl_simple_timer(hl_loop);
                exit_ch_clone.send(());
            });
        };
        for iter::repeat(cycles) {
            exit_po.recv();
        };
        log(debug, ~"test_stress_gl_uv_global_loop_high_level_global_timer"+
            ~" exiting sucessfully!");
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

//! See docs in build/expr/mod.rs

use build::{BlockAnd, BlockAndExtension, Builder};
use build::expr::category::{Category, RvalueFunc};
use hair::*;
use rustc::ty;
use rustc::mir::repr::*;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
    /// Compile `expr`, storing the result into `destination`, which
    /// is assumed to be uninitialized.
    pub fn into_expr(&mut self,
                     destination: &Lvalue<'tcx>,
                     mut block: BasicBlock,
                     expr: Expr<'tcx>)
                     -> BlockAnd<()>
    {
        debug!("into_expr(destination={:?}, block={:?}, expr={:?})",
               destination, block, expr);

        // since we frequently have to reference `self` from within a
        // closure, where `self` would be shadowed, it's easier to
        // just use the name `this` uniformly
        let this = self;
        let expr_span = expr.span;
        let source_info = this.source_info(expr_span);

        match expr.kind {
            ExprKind::Scope { extent, value } => {
                this.in_scope(extent, block, |this| this.into(destination, block, value))
            }
            ExprKind::Block { body: ast_block } => {
                this.ast_block(destination, expr.ty.is_nil(), block, ast_block)
            }
            ExprKind::Match { discriminant, arms } => {
                this.match_expr(destination, expr_span, block, discriminant, arms)
            }
            ExprKind::EmptyToAny { source } => {
                // TODO(canndrew): Do we need to do this?
                unpack!(block = this.as_rvalue(block, source));

                this.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
                let end_block = this.cfg.start_new_block();
                end_block.unit()
            }
            ExprKind::If { condition: cond_expr, then: then_expr, otherwise: else_expr } => {
                let operand = unpack!(block = this.as_operand(block, cond_expr));

                let mut then_block = this.cfg.start_new_block();
                let mut else_block = this.cfg.start_new_block();
                this.cfg.terminate(block, source_info, TerminatorKind::If {
                    cond: operand,
                    targets: (then_block, else_block)
                });

                unpack!(then_block = this.into(destination, then_block, then_expr));
                else_block = if let Some(else_expr) = else_expr {
                    unpack!(this.into(destination, else_block, else_expr))
                } else {
                    // Body of the `if` expression without an `else` clause must return `()`, thus
                    // we implicitly generate a `else {}` if it is not specified.
                    this.cfg.push_assign_unit(else_block, source_info, destination);
                    else_block
                };

                let join_block = this.cfg.start_new_block();
                this.cfg.terminate(then_block, source_info,
                                   TerminatorKind::Goto { target: join_block });
                this.cfg.terminate(else_block, source_info,
                                   TerminatorKind::Goto { target: join_block });

                join_block.unit()
            }
            ExprKind::LogicalOp { op, lhs, rhs } => {
                // And:
                //
                // [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block]
                //        |                          | (false)
                //        +----------false-----------+------------------> [false_block]
                //
                // Or:
                //
                // [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block]
                //        |                          | (false)
                //        +----------true------------+-------------------> [false_block]

                let (true_block, false_block, mut else_block, join_block) =
                    (this.cfg.start_new_block(), this.cfg.start_new_block(),
                     this.cfg.start_new_block(), this.cfg.start_new_block());

                let lhs = unpack!(block = this.as_operand(block, lhs));
                let blocks = match op {
                    LogicalOp::And => (else_block, false_block),
                    LogicalOp::Or => (true_block, else_block),
                };
                this.cfg.terminate(block, source_info,
                                   TerminatorKind::If { cond: lhs, targets: blocks });

                let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
                this.cfg.terminate(else_block, source_info, TerminatorKind::If {
                    cond: rhs,
                    targets: (true_block, false_block)
                });

                this.cfg.push_assign_constant(
                    true_block, source_info, destination,
                    Constant {
                        span: expr_span,
                        ty: this.hir.bool_ty(),
                        literal: this.hir.true_literal(),
                    });

                this.cfg.push_assign_constant(
                    false_block, source_info, destination,
                    Constant {
                        span: expr_span,
                        ty: this.hir.bool_ty(),
                        literal: this.hir.false_literal(),
                    });

                this.cfg.terminate(true_block, source_info,
                                   TerminatorKind::Goto { target: join_block });
                this.cfg.terminate(false_block, source_info,
                                   TerminatorKind::Goto { target: join_block });

                join_block.unit()
            }
            ExprKind::Loop { condition: opt_cond_expr, body } => {
                // [block] --> [loop_block] ~~> [loop_block_end] -1-> [exit_block]
                //                  ^                  |
                //                  |                  0
                //                  |                  |
                //                  |                  v
                //           [body_block_end] <~~~ [body_block]
                //
                // If `opt_cond_expr` is `None`, then the graph is somewhat simplified:
                //
                // [block] --> [loop_block / body_block ] ~~> [body_block_end]    [exit_block]
                //                         ^                          |
                //                         |                          |
                //                         +--------------------------+
                //

                let loop_block = this.cfg.start_new_block();
                let exit_block = this.cfg.start_new_block();

                // start the loop
                this.cfg.terminate(block, source_info,
                                   TerminatorKind::Goto { target: loop_block });

                let might_break = this.in_loop_scope(loop_block, exit_block, move |this| {
                    // conduct the test, if necessary
                    let body_block;
                    if let Some(cond_expr) = opt_cond_expr {
                        // This loop has a condition, ergo its exit_block is reachable.
                        this.find_loop_scope(expr_span, None).might_break = true;

                        let loop_block_end;
                        let cond = unpack!(loop_block_end = this.as_operand(loop_block, cond_expr));
                        body_block = this.cfg.start_new_block();
                        this.cfg.terminate(loop_block_end, source_info,
                                           TerminatorKind::If {
                                               cond: cond,
                                               targets: (body_block, exit_block)
                                           });
                    } else {
                        body_block = loop_block;
                    }

                    // The “return” value of the loop body must always be an unit, but we cannot
                    // reuse that as a “return” value of the whole loop expressions, because some
                    // loops are diverging (e.g. `loop {}`). Thus, we introduce a unit temporary as
                    // the destination for the loop body and assign the loop’s own “return” value
                    // immediately after the iteration is finished.
                    let tmp = this.get_unit_temp();
                    // Execute the body, branching back to the test.
                    let body_block_end = unpack!(this.into(&tmp, body_block, body));
                    this.cfg.terminate(body_block_end, source_info,
                                       TerminatorKind::Goto { target: loop_block });
                });
                // If the loop may reach its exit_block, we assign an empty tuple to the
                // destination to keep the MIR well-formed.
                if might_break {
                    this.cfg.push_assign_unit(exit_block, source_info, destination);
                }
                exit_block.unit()
            }
            ExprKind::Call { ty, fun, args } => {
                let diverges = match ty.sty {
                    ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
                        f.sig.0.output.diverges()
                    }
                    _ => false
                };
                let fun = unpack!(block = this.as_operand(block, fun));
                let args: Vec<_> =
                    args.into_iter()
                        .map(|arg| unpack!(block = this.as_operand(block, arg)))
                        .collect();

                let success = this.cfg.start_new_block();
                let cleanup = this.diverge_cleanup();
                this.cfg.terminate(block, source_info, TerminatorKind::Call {
                    func: fun,
                    args: args,
                    cleanup: cleanup,
                    destination: if diverges {
                        None
                    } else {
                        Some ((destination.clone(), success))
                    }
                });
                success.unit()
            }

            // These cases don't actually need a destination
            ExprKind::Assign { .. } |
            ExprKind::AssignOp { .. } |
            ExprKind::Continue { .. } |
            ExprKind::Break { .. } |
            ExprKind::Return {.. } => {
                this.stmt_expr(block, expr)
            }

            // these are the cases that are more naturally handled by some other mode
            ExprKind::Unary { .. } |
            ExprKind::Binary { .. } |
            ExprKind::Box { .. } |
            ExprKind::Cast { .. } |
            ExprKind::ReifyFnPointer { .. } |
            ExprKind::UnsafeFnPointer { .. } |
            ExprKind::Unsize { .. } |
            ExprKind::Repeat { .. } |
            ExprKind::Borrow { .. } |
            ExprKind::VarRef { .. } |
            ExprKind::SelfRef |
            ExprKind::StaticRef { .. } |
            ExprKind::Vec { .. } |
            ExprKind::Tuple { .. } |
            ExprKind::Adt { .. } |
            ExprKind::Closure { .. } |
            ExprKind::Index { .. } |
            ExprKind::Deref { .. } |
            ExprKind::Literal { .. } |
            ExprKind::InlineAsm { .. } |
            ExprKind::Field { .. } => {
                debug_assert!(match Category::of(&expr.kind).unwrap() {
                    Category::Rvalue(RvalueFunc::Into) => false,
                    _ => true,
                });

                let rvalue = unpack!(block = this.as_rvalue(block, expr));
                this.cfg.push_assign(block, source_info, destination, rvalue);
                block.unit()
            }
        }
    }
}
<commit_msg>Small optimization<commit_after>// Copyright 2015 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.

//! See docs in build/expr/mod.rs

use build::{BlockAnd, BlockAndExtension, Builder};
use build::expr::category::{Category, RvalueFunc};
use hair::*;
use rustc::ty;
use rustc::mir::repr::*;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
    /// Compile `expr`, storing the result into `destination`, which
    /// is assumed to be uninitialized.
    pub fn into_expr(&mut self,
                     destination: &Lvalue<'tcx>,
                     mut block: BasicBlock,
                     expr: Expr<'tcx>)
                     -> BlockAnd<()>
    {
        debug!("into_expr(destination={:?}, block={:?}, expr={:?})",
               destination, block, expr);

        // since we frequently have to reference `self` from within a
        // closure, where `self` would be shadowed, it's easier to
        // just use the name `this` uniformly
        let this = self;
        let expr_span = expr.span;
        let source_info = this.source_info(expr_span);

        match expr.kind {
            ExprKind::Scope { extent, value } => {
                this.in_scope(extent, block, |this| this.into(destination, block, value))
            }
            ExprKind::Block { body: ast_block } => {
                this.ast_block(destination, expr.ty.is_nil(), block, ast_block)
            }
            ExprKind::Match { discriminant, arms } => {
                this.match_expr(destination, expr_span, block, discriminant, arms)
            }
            ExprKind::EmptyToAny { source } => {
                let source = this.hir.mirror(source);
                let is_call = match source.kind {
                    ExprKind::Call { .. } => true,
                    _ => false,
                };

                unpack!(block = this.as_rvalue(block, source));

                // This is an optimization. If the expression was a call then we already have an
                // unreachable block. Don't bother to terminate it and create a new one.
                if is_call {
                    block.unit()
                }
                else {
                    this.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
                    let end_block = this.cfg.start_new_block();
                    end_block.unit()
                }
            }
            ExprKind::If { condition: cond_expr, then: then_expr, otherwise: else_expr } => {
                let operand = unpack!(block = this.as_operand(block, cond_expr));

                let mut then_block = this.cfg.start_new_block();
                let mut else_block = this.cfg.start_new_block();
                this.cfg.terminate(block, source_info, TerminatorKind::If {
                    cond: operand,
                    targets: (then_block, else_block)
                });

                unpack!(then_block = this.into(destination, then_block, then_expr));
                else_block = if let Some(else_expr) = else_expr {
                    unpack!(this.into(destination, else_block, else_expr))
                } else {
                    // Body of the `if` expression without an `else` clause must return `()`, thus
                    // we implicitly generate a `else {}` if it is not specified.
                    this.cfg.push_assign_unit(else_block, source_info, destination);
                    else_block
                };

                let join_block = this.cfg.start_new_block();
                this.cfg.terminate(then_block, source_info,
                                   TerminatorKind::Goto { target: join_block });
                this.cfg.terminate(else_block, source_info,
                                   TerminatorKind::Goto { target: join_block });

                join_block.unit()
            }
            ExprKind::LogicalOp { op, lhs, rhs } => {
                // And:
                //
                // [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block]
                //        |                          | (false)
                //        +----------false-----------+------------------> [false_block]
                //
                // Or:
                //
                // [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block]
                //        |                          | (false)
                //        +----------true------------+-------------------> [false_block]

                let (true_block, false_block, mut else_block, join_block) =
                    (this.cfg.start_new_block(), this.cfg.start_new_block(),
                     this.cfg.start_new_block(), this.cfg.start_new_block());

                let lhs = unpack!(block = this.as_operand(block, lhs));
                let blocks = match op {
                    LogicalOp::And => (else_block, false_block),
                    LogicalOp::Or => (true_block, else_block),
                };
                this.cfg.terminate(block, source_info,
                                   TerminatorKind::If { cond: lhs, targets: blocks });

                let rhs = unpack!(else_block = this.as_operand(else_block, rhs));
                this.cfg.terminate(else_block, source_info, TerminatorKind::If {
                    cond: rhs,
                    targets: (true_block, false_block)
                });

                this.cfg.push_assign_constant(
                    true_block, source_info, destination,
                    Constant {
                        span: expr_span,
                        ty: this.hir.bool_ty(),
                        literal: this.hir.true_literal(),
                    });

                this.cfg.push_assign_constant(
                    false_block, source_info, destination,
                    Constant {
                        span: expr_span,
                        ty: this.hir.bool_ty(),
                        literal: this.hir.false_literal(),
                    });

                this.cfg.terminate(true_block, source_info,
                                   TerminatorKind::Goto { target: join_block });
                this.cfg.terminate(false_block, source_info,
                                   TerminatorKind::Goto { target: join_block });

                join_block.unit()
            }
            ExprKind::Loop { condition: opt_cond_expr, body } => {
                // [block] --> [loop_block] ~~> [loop_block_end] -1-> [exit_block]
                //                  ^                  |
                //                  |                  0
                //                  |                  |
                //                  |                  v
                //           [body_block_end] <~~~ [body_block]
                //
                // If `opt_cond_expr` is `None`, then the graph is somewhat simplified:
                //
                // [block] --> [loop_block / body_block ] ~~> [body_block_end]    [exit_block]
                //                         ^                          |
                //                         |                          |
                //                         +--------------------------+
                //

                let loop_block = this.cfg.start_new_block();
                let exit_block = this.cfg.start_new_block();

                // start the loop
                this.cfg.terminate(block, source_info,
                                   TerminatorKind::Goto { target: loop_block });

                let might_break = this.in_loop_scope(loop_block, exit_block, move |this| {
                    // conduct the test, if necessary
                    let body_block;
                    if let Some(cond_expr) = opt_cond_expr {
                        // This loop has a condition, ergo its exit_block is reachable.
                        this.find_loop_scope(expr_span, None).might_break = true;

                        let loop_block_end;
                        let cond = unpack!(loop_block_end = this.as_operand(loop_block, cond_expr));
                        body_block = this.cfg.start_new_block();
                        this.cfg.terminate(loop_block_end, source_info,
                                           TerminatorKind::If {
                                               cond: cond,
                                               targets: (body_block, exit_block)
                                           });
                    } else {
                        body_block = loop_block;
                    }

                    // The “return” value of the loop body must always be an unit, but we cannot
                    // reuse that as a “return” value of the whole loop expressions, because some
                    // loops are diverging (e.g. `loop {}`). Thus, we introduce a unit temporary as
                    // the destination for the loop body and assign the loop’s own “return” value
                    // immediately after the iteration is finished.
                    let tmp = this.get_unit_temp();
                    // Execute the body, branching back to the test.
                    let body_block_end = unpack!(this.into(&tmp, body_block, body));
                    this.cfg.terminate(body_block_end, source_info,
                                       TerminatorKind::Goto { target: loop_block });
                });
                // If the loop may reach its exit_block, we assign an empty tuple to the
                // destination to keep the MIR well-formed.
                if might_break {
                    this.cfg.push_assign_unit(exit_block, source_info, destination);
                }
                exit_block.unit()
            }
            ExprKind::Call { ty, fun, args } => {
                let diverges = match ty.sty {
                    ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
                        f.sig.0.output.diverges()
                    }
                    _ => false
                };
                let fun = unpack!(block = this.as_operand(block, fun));
                let args: Vec<_> =
                    args.into_iter()
                        .map(|arg| unpack!(block = this.as_operand(block, arg)))
                        .collect();

                let success = this.cfg.start_new_block();
                let cleanup = this.diverge_cleanup();
                this.cfg.terminate(block, source_info, TerminatorKind::Call {
                    func: fun,
                    args: args,
                    cleanup: cleanup,
                    destination: if diverges {
                        None
                    } else {
                        Some ((destination.clone(), success))
                    }
                });
                success.unit()
            }

            // These cases don't actually need a destination
            ExprKind::Assign { .. } |
            ExprKind::AssignOp { .. } |
            ExprKind::Continue { .. } |
            ExprKind::Break { .. } |
            ExprKind::Return {.. } => {
                this.stmt_expr(block, expr)
            }

            // these are the cases that are more naturally handled by some other mode
            ExprKind::Unary { .. } |
            ExprKind::Binary { .. } |
            ExprKind::Box { .. } |
            ExprKind::Cast { .. } |
            ExprKind::ReifyFnPointer { .. } |
            ExprKind::UnsafeFnPointer { .. } |
            ExprKind::Unsize { .. } |
            ExprKind::Repeat { .. } |
            ExprKind::Borrow { .. } |
            ExprKind::VarRef { .. } |
            ExprKind::SelfRef |
            ExprKind::StaticRef { .. } |
            ExprKind::Vec { .. } |
            ExprKind::Tuple { .. } |
            ExprKind::Adt { .. } |
            ExprKind::Closure { .. } |
            ExprKind::Index { .. } |
            ExprKind::Deref { .. } |
            ExprKind::Literal { .. } |
            ExprKind::InlineAsm { .. } |
            ExprKind::Field { .. } => {
                debug_assert!(match Category::of(&expr.kind).unwrap() {
                    Category::Rvalue(RvalueFunc::Into) => false,
                    _ => true,
                });

                let rvalue = unpack!(block = this.as_rvalue(block, expr));
                this.cfg.push_assign(block, source_info, destination, rvalue);
                block.unit()
            }
        }
    }
}
<|endoftext|>


<commit_before>use super::diagnostics::Error;
use super::item::ItemInfo;
use super::Parser;

use crate::{new_sub_parser_from_file, DirectoryOwnership};

use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod};
use rustc_ast::attr;
use rustc_ast::token::{self, TokenKind};
use rustc_errors::PResult;
use rustc_span::source_map::{FileName, SourceMap, Span, DUMMY_SP};
use rustc_span::symbol::sym;

use std::path::{self, Path, PathBuf};

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath {
    name: String,
    path_exists: bool,
    pub result: Result<ModulePathSuccess, Error>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub path: PathBuf,
    pub directory_ownership: DirectoryOwnership,
}

impl<'a> Parser<'a> {
    /// Parses a source module as a crate. This is the main entry point for the parser.
    pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> {
        let lo = self.token.span;
        let krate = Ok(ast::Crate {
            attrs: self.parse_inner_attributes()?,
            module: self.parse_mod_items(&token::Eof, lo)?,
            span: lo.to(self.token.span),
            // Filled in by proc_macro_harness::inject()
            proc_macros: Vec::new(),
        });
        krate
    }

    /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
    pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
        let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs);

        let id_span = self.token.span;
        let id = self.parse_ident()?;
        let (module, mut inner_attrs) = if self.eat(&token::Semi) {
            if in_cfg && self.recurse_into_file_modules {
                // This mod is in an external file. Let's go get it!
                let ModulePathSuccess { path, directory_ownership } =
                    self.submod_path(id, &attrs, id_span)?;
                self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)?
            } else {
                (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new())
            }
        } else {
            let old_directory = self.directory.clone();
            self.push_directory(id, &attrs);

            self.expect(&token::OpenDelim(token::Brace))?;
            let mod_inner_lo = self.token.span;
            let inner_attrs = self.parse_inner_attributes()?;
            let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;

            self.directory = old_directory;
            (module, inner_attrs)
        };
        attrs.append(&mut inner_attrs);
        Ok((id, ItemKind::Mod(module)))
    }

    /// Given a termination token, parses all of the items in a module.
    fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> {
        let mut items = vec![];
        while let Some(item) = self.parse_item()? {
            items.push(item);
            self.maybe_consume_incorrect_semicolon(&items);
        }

        if !self.eat(term) {
            let token_str = super::token_descr(&self.token);
            if !self.maybe_consume_incorrect_semicolon(&items) {
                let msg = &format!("expected item, found {}", token_str);
                let mut err = self.struct_span_err(self.token.span, msg);
                err.span_label(self.token.span, "expected item");
                return Err(err);
            }
        }

        let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };

        Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
    }

    fn submod_path(
        &mut self,
        id: ast::Ident,
        outer_attrs: &[Attribute],
        id_sp: Span,
    ) -> PResult<'a, ModulePathSuccess> {
        if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) {
            return Ok(ModulePathSuccess {
                directory_ownership: match path.file_name().and_then(|s| s.to_str()) {
                    // All `#[path]` files are treated as though they are a `mod.rs` file.
                    // This means that `mod foo;` declarations inside `#[path]`-included
                    // files are siblings,
                    //
                    // Note that this will produce weirdness when a file named `foo.rs` is
                    // `#[path]` included and contains a `mod foo;` declaration.
                    // If you encounter this, it's your own darn fault :P
                    Some(_) => DirectoryOwnership::Owned { relative: None },
                    _ => DirectoryOwnership::UnownedViaMod,
                },
                path,
            });
        }

        let relative = match self.directory.ownership {
            DirectoryOwnership::Owned { relative } => relative,
            DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
        };
        let paths =
            Parser::default_submod_path(id, relative, &self.directory.path, self.sess.source_map());

        match self.directory.ownership {
            DirectoryOwnership::Owned { .. } => {
                paths.result.map_err(|err| self.span_fatal_err(id_sp, err))
            }
            DirectoryOwnership::UnownedViaBlock => {
                let msg = "Cannot declare a non-inline module inside a block \
                    unless it has a path attribute";
                let mut err = self.struct_span_err(id_sp, msg);
                if paths.path_exists {
                    let msg = format!(
                        "Maybe `use` the module `{}` instead of redeclaring it",
                        paths.name
                    );
                    err.span_note(id_sp, &msg);
                }
                Err(err)
            }
            DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id_sp, paths),
        }
    }

    fn error_cannot_declare_mod_here<T>(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> {
        let mut err = self.struct_span_err(id_sp, "cannot declare a new module at this location");
        if !id_sp.is_dummy() {
            if let FileName::Real(src_path) = self.sess.source_map().span_to_filename(id_sp) {
                if let Some(stem) = src_path.file_stem() {
                    let mut dest_path = src_path.clone();
                    dest_path.set_file_name(stem);
                    dest_path.push("mod.rs");
                    err.span_note(
                        id_sp,
                        &format!(
                            "maybe move this module `{}` to its own \
                                    directory via `{}`",
                            src_path.display(),
                            dest_path.display()
                        ),
                    );
                }
            }
        }
        if paths.path_exists {
            err.span_note(
                id_sp,
                &format!(
                    "... or maybe `use` the module `{}` instead \
                                of possibly redeclaring it",
                    paths.name
                ),
            );
        }
        Err(err)
    }

    /// Derive a submodule path from the first found `#[path = "path_string"]`.
    /// The provided `dir_path` is joined with the `path_string`.
    // Public for rustfmt usage.
    pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
        // Extract path string from first `#[path = "path_string"]` attribute.
        let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
        let path_string = path_string.as_str();

        // On windows, the base path might have the form
        // `\\?\foo\bar` in which case it does not tolerate
        // mixed `/` and `\` separators, so canonicalize
        // `/` to `\`.
        #[cfg(windows)]
        let path_string = path_string.replace("/", "\\");

        Some(dir_path.join(&*path_string))
    }

    /// Returns a path to a module.
    // Public for rustfmt usage.
    pub fn default_submod_path(
        id: ast::Ident,
        relative: Option<ast::Ident>,
        dir_path: &Path,
        source_map: &SourceMap,
    ) -> ModulePath {
        // If we're in a foo.rs file instead of a mod.rs file,
        // we need to look for submodules in
        // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
        // `./<id>.rs` and `./<id>/mod.rs`.
        let relative_prefix_string;
        let relative_prefix = if let Some(ident) = relative {
            relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
            &relative_prefix_string
        } else {
            ""
        };

        let mod_name = id.name.to_string();
        let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
        let secondary_path_str =
            format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
        let default_path = dir_path.join(&default_path_str);
        let secondary_path = dir_path.join(&secondary_path_str);
        let default_exists = source_map.file_exists(&default_path);
        let secondary_exists = source_map.file_exists(&secondary_path);

        let result = match (default_exists, secondary_exists) {
            (true, false) => Ok(ModulePathSuccess {
                path: default_path,
                directory_ownership: DirectoryOwnership::Owned { relative: Some(id) },
            }),
            (false, true) => Ok(ModulePathSuccess {
                path: secondary_path,
                directory_ownership: DirectoryOwnership::Owned { relative: None },
            }),
            (false, false) => {
                Err(Error::FileNotFoundForModule { mod_name: mod_name.clone(), default_path })
            }
            (true, true) => Err(Error::DuplicatePaths {
                mod_name: mod_name.clone(),
                default_path: default_path_str,
                secondary_path: secondary_path_str,
            }),
        };

        ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
    }

    /// Reads a module from a source file.
    fn eval_src_mod(
        &mut self,
        path: PathBuf,
        directory_ownership: DirectoryOwnership,
        name: String,
        id_sp: Span,
    ) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut();
        if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
            let mut err = String::from("circular modules: ");
            let len = included_mod_stack.len();
            for p in &included_mod_stack[i..len] {
                err.push_str(&p.to_string_lossy());
                err.push_str(" -> ");
            }
            err.push_str(&path.to_string_lossy());
            return Err(self.struct_span_err(id_sp, &err[..]));
        }
        included_mod_stack.push(path.clone());
        drop(included_mod_stack);

        let mut p0 =
            new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp);
        p0.cfg_mods = self.cfg_mods;
        let mod_inner_lo = p0.token.span;
        let mod_attrs = p0.parse_inner_attributes()?;
        let mut m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?;
        m0.inline = false;
        self.sess.included_mod_stack.borrow_mut().pop();
        Ok((m0, mod_attrs))
    }

    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
        if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) {
            self.directory.path.push(&*path.as_str());
            self.directory.ownership = DirectoryOwnership::Owned { relative: None };
        } else {
            // We have to push on the current module name in the case of relative
            // paths in order to ensure that any additional module paths from inline
            // `mod x { ... }` come after the relative extension.
            //
            // For example, a `mod z { ... }` inside `x/y.rs` should set the current
            // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
            if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership {
                if let Some(ident) = relative.take() {
                    // remove the relative offset
                    self.directory.path.push(&*ident.as_str());
                }
            }
            self.directory.path.push(&*id.as_str());
        }
    }
}
<commit_msg>extract error_decl_mod_in_block<commit_after>use super::diagnostics::Error;
use super::item::ItemInfo;
use super::Parser;

use crate::{new_sub_parser_from_file, DirectoryOwnership};

use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod};
use rustc_ast::attr;
use rustc_ast::token::{self, TokenKind};
use rustc_errors::PResult;
use rustc_span::source_map::{FileName, SourceMap, Span, DUMMY_SP};
use rustc_span::symbol::sym;

use std::path::{self, Path, PathBuf};

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath {
    name: String,
    path_exists: bool,
    pub result: Result<ModulePathSuccess, Error>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub path: PathBuf,
    pub directory_ownership: DirectoryOwnership,
}

impl<'a> Parser<'a> {
    /// Parses a source module as a crate. This is the main entry point for the parser.
    pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> {
        let lo = self.token.span;
        let krate = Ok(ast::Crate {
            attrs: self.parse_inner_attributes()?,
            module: self.parse_mod_items(&token::Eof, lo)?,
            span: lo.to(self.token.span),
            // Filled in by proc_macro_harness::inject()
            proc_macros: Vec::new(),
        });
        krate
    }

    /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
    pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
        let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs);

        let id_span = self.token.span;
        let id = self.parse_ident()?;
        let (module, mut inner_attrs) = if self.eat(&token::Semi) {
            if in_cfg && self.recurse_into_file_modules {
                // This mod is in an external file. Let's go get it!
                let ModulePathSuccess { path, directory_ownership } =
                    self.submod_path(id, &attrs, id_span)?;
                self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)?
            } else {
                (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new())
            }
        } else {
            let old_directory = self.directory.clone();
            self.push_directory(id, &attrs);

            self.expect(&token::OpenDelim(token::Brace))?;
            let mod_inner_lo = self.token.span;
            let inner_attrs = self.parse_inner_attributes()?;
            let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;

            self.directory = old_directory;
            (module, inner_attrs)
        };
        attrs.append(&mut inner_attrs);
        Ok((id, ItemKind::Mod(module)))
    }

    /// Given a termination token, parses all of the items in a module.
    fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> {
        let mut items = vec![];
        while let Some(item) = self.parse_item()? {
            items.push(item);
            self.maybe_consume_incorrect_semicolon(&items);
        }

        if !self.eat(term) {
            let token_str = super::token_descr(&self.token);
            if !self.maybe_consume_incorrect_semicolon(&items) {
                let msg = &format!("expected item, found {}", token_str);
                let mut err = self.struct_span_err(self.token.span, msg);
                err.span_label(self.token.span, "expected item");
                return Err(err);
            }
        }

        let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };

        Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
    }

    fn submod_path(
        &mut self,
        id: ast::Ident,
        outer_attrs: &[Attribute],
        id_sp: Span,
    ) -> PResult<'a, ModulePathSuccess> {
        if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) {
            return Ok(ModulePathSuccess {
                directory_ownership: match path.file_name().and_then(|s| s.to_str()) {
                    // All `#[path]` files are treated as though they are a `mod.rs` file.
                    // This means that `mod foo;` declarations inside `#[path]`-included
                    // files are siblings,
                    //
                    // Note that this will produce weirdness when a file named `foo.rs` is
                    // `#[path]` included and contains a `mod foo;` declaration.
                    // If you encounter this, it's your own darn fault :P
                    Some(_) => DirectoryOwnership::Owned { relative: None },
                    _ => DirectoryOwnership::UnownedViaMod,
                },
                path,
            });
        }

        let relative = match self.directory.ownership {
            DirectoryOwnership::Owned { relative } => relative,
            DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
        };
        let paths =
            Parser::default_submod_path(id, relative, &self.directory.path, self.sess.source_map());

        match self.directory.ownership {
            DirectoryOwnership::Owned { .. } => {
                paths.result.map_err(|err| self.span_fatal_err(id_sp, err))
            }
            DirectoryOwnership::UnownedViaBlock => self.error_decl_mod_in_block(id_sp, paths),
            DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id_sp, paths),
        }
    }

    fn error_decl_mod_in_block<T>(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> {
        let msg =
            "Cannot declare a non-inline module inside a block unless it has a path attribute";
        let mut err = self.struct_span_err(id_sp, msg);
        if paths.path_exists {
            let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", paths.name);
            err.span_note(id_sp, &msg);
        }
        Err(err)
    }

    fn error_cannot_declare_mod_here<T>(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> {
        let mut err = self.struct_span_err(id_sp, "cannot declare a new module at this location");
        if !id_sp.is_dummy() {
            if let FileName::Real(src_path) = self.sess.source_map().span_to_filename(id_sp) {
                if let Some(stem) = src_path.file_stem() {
                    let mut dest_path = src_path.clone();
                    dest_path.set_file_name(stem);
                    dest_path.push("mod.rs");
                    err.span_note(
                        id_sp,
                        &format!(
                            "maybe move this module `{}` to its own \
                                    directory via `{}`",
                            src_path.display(),
                            dest_path.display()
                        ),
                    );
                }
            }
        }
        if paths.path_exists {
            err.span_note(
                id_sp,
                &format!(
                    "... or maybe `use` the module `{}` instead \
                                of possibly redeclaring it",
                    paths.name
                ),
            );
        }
        Err(err)
    }

    /// Derive a submodule path from the first found `#[path = "path_string"]`.
    /// The provided `dir_path` is joined with the `path_string`.
    // Public for rustfmt usage.
    pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
        // Extract path string from first `#[path = "path_string"]` attribute.
        let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
        let path_string = path_string.as_str();

        // On windows, the base path might have the form
        // `\\?\foo\bar` in which case it does not tolerate
        // mixed `/` and `\` separators, so canonicalize
        // `/` to `\`.
        #[cfg(windows)]
        let path_string = path_string.replace("/", "\\");

        Some(dir_path.join(&*path_string))
    }

    /// Returns a path to a module.
    // Public for rustfmt usage.
    pub fn default_submod_path(
        id: ast::Ident,
        relative: Option<ast::Ident>,
        dir_path: &Path,
        source_map: &SourceMap,
    ) -> ModulePath {
        // If we're in a foo.rs file instead of a mod.rs file,
        // we need to look for submodules in
        // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
        // `./<id>.rs` and `./<id>/mod.rs`.
        let relative_prefix_string;
        let relative_prefix = if let Some(ident) = relative {
            relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
            &relative_prefix_string
        } else {
            ""
        };

        let mod_name = id.name.to_string();
        let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
        let secondary_path_str =
            format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
        let default_path = dir_path.join(&default_path_str);
        let secondary_path = dir_path.join(&secondary_path_str);
        let default_exists = source_map.file_exists(&default_path);
        let secondary_exists = source_map.file_exists(&secondary_path);

        let result = match (default_exists, secondary_exists) {
            (true, false) => Ok(ModulePathSuccess {
                path: default_path,
                directory_ownership: DirectoryOwnership::Owned { relative: Some(id) },
            }),
            (false, true) => Ok(ModulePathSuccess {
                path: secondary_path,
                directory_ownership: DirectoryOwnership::Owned { relative: None },
            }),
            (false, false) => {
                Err(Error::FileNotFoundForModule { mod_name: mod_name.clone(), default_path })
            }
            (true, true) => Err(Error::DuplicatePaths {
                mod_name: mod_name.clone(),
                default_path: default_path_str,
                secondary_path: secondary_path_str,
            }),
        };

        ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
    }

    /// Reads a module from a source file.
    fn eval_src_mod(
        &mut self,
        path: PathBuf,
        directory_ownership: DirectoryOwnership,
        name: String,
        id_sp: Span,
    ) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut();
        if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
            let mut err = String::from("circular modules: ");
            let len = included_mod_stack.len();
            for p in &included_mod_stack[i..len] {
                err.push_str(&p.to_string_lossy());
                err.push_str(" -> ");
            }
            err.push_str(&path.to_string_lossy());
            return Err(self.struct_span_err(id_sp, &err[..]));
        }
        included_mod_stack.push(path.clone());
        drop(included_mod_stack);

        let mut p0 =
            new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp);
        p0.cfg_mods = self.cfg_mods;
        let mod_inner_lo = p0.token.span;
        let mod_attrs = p0.parse_inner_attributes()?;
        let mut m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?;
        m0.inline = false;
        self.sess.included_mod_stack.borrow_mut().pop();
        Ok((m0, mod_attrs))
    }

    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
        if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) {
            self.directory.path.push(&*path.as_str());
            self.directory.ownership = DirectoryOwnership::Owned { relative: None };
        } else {
            // We have to push on the current module name in the case of relative
            // paths in order to ensure that any additional module paths from inline
            // `mod x { ... }` come after the relative extension.
            //
            // For example, a `mod z { ... }` inside `x/y.rs` should set the current
            // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
            if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership {
                if let Some(ident) = relative.take() {
                    // remove the relative offset
                    self.directory.path.push(&*ident.as_str());
                }
            }
            self.directory.path.push(&*id.as_str());
        }
    }
}
<|endoftext|>


<commit_before>use std::str;
use std::thread;
use std::sync::Mutex;
use std::cell::RefCell;
use std::time::{Duration,Instant};
use std::iter::repeat;
use std::collections::BTreeMap;
use std::collections::VecDeque;
use std::fmt::Arguments;
use std::net::SocketAddr;
use mio::net::UdpSocket;
use std::io::{self,BufWriter,Write,Error,ErrorKind};
use nom::HexDisplay;
use hdrhistogram::Histogram;
use sozu_command::buffer::Buffer;
use sozu_command::messages::{FilteredData,MetricsData,Percentiles,BackendMetricsData,FilteredTimeSerie};

mod network_drain;
mod local_drain;

use self::network_drain::NetworkDrain;
use self::local_drain::LocalDrain;

thread_local! {
  pub static METRICS: RefCell<Aggregator> = RefCell::new(Aggregator::new(String::from("sozu")));
}

#[derive(Debug,Clone,PartialEq)]
pub enum MetricData {
  Gauge(usize),
  GaugeAdd(i64),
  Count(i64),
  Time(usize),
}

impl MetricData {
  fn is_time(&self) -> bool {
    match self {
      &MetricData::Time(_) => true,
      _ => false,
    }
  }

  fn update(&mut self, key: &'static str, m: MetricData) {
    match (self, m) {
      (&mut MetricData::Gauge(ref mut v1), MetricData::Gauge(v2)) => {
        *v1 = v2;
      },
      (&mut MetricData::Gauge(ref mut v1), MetricData::GaugeAdd(v2)) => {
        *v1 = (*v1 as i64 + v2) as usize;
      },
      (&mut MetricData::Count(ref mut v1), MetricData::Count(v2)) => {
        *v1 += v2;
      },
      (s,m) => panic!("tried to update metric {} of value {:?} with an incompatible metric: {:?}", key, s, m)
    }
  }
}

#[derive(Debug,Clone)]
pub struct StoredMetricData {
  last_sent: Instant,
  data:      MetricData,
}

impl StoredMetricData {
  pub fn new(last_sent: Instant, data: MetricData) -> StoredMetricData {
    StoredMetricData {
      last_sent: last_sent,
      data: if let MetricData::GaugeAdd(v) = data {
        MetricData::Gauge(v as usize)
      } else { data }
    }
  }
}

pub fn setup<H: AsRef<str>, O: Into<String>>(host: H, port: u16, origin: O, use_tagged_metrics: bool) {
  use std::net::ToSocketAddrs;
  let metrics_socket = udp_bind();

  debug!("setting up metrics: local address = {:#?}", metrics_socket.local_addr());
  let metrics_host   = (host.as_ref(), port).to_socket_addrs().expect("could not parse address").next().expect("could not get first address");

  METRICS.with(|metrics| {
    (*metrics.borrow_mut()).set_up_remote(metrics_socket, metrics_host);
    (*metrics.borrow_mut()).set_up_origin(origin.into());
    (*metrics.borrow_mut()).set_up_tagged_metrics(use_tagged_metrics);
  });
}

pub trait Subscriber {
  fn receive_metric(&mut self, label: &'static str, app_id: Option<&str>, backend_id: Option<&str>, metric: MetricData);
}

pub struct Aggregator {
  prefix:  String,
  network: Option<NetworkDrain>,
  local:   LocalDrain,
}

impl Aggregator {
  pub fn new(prefix: String) -> Aggregator {
    Aggregator {
      prefix: prefix.clone(),
      network: None,
      local: LocalDrain::new(prefix),
    }
  }

  pub fn set_up_remote(&mut self, socket: UdpSocket, addr: SocketAddr) {
    self.network = Some(NetworkDrain::new(self.prefix.clone(), socket, addr));
  }

  pub fn set_up_origin(&mut self, origin: String) {
    self.network.as_mut().map(|n| n.origin = origin);
  }

  pub fn set_up_tagged_metrics(&mut self, tagged: bool) {
    self.network.as_mut().map(|n| n.use_tagged_metrics = tagged);
  }

  pub fn socket(&self) -> Option<&UdpSocket> {
    self.network.as_ref().map(|n| &n.remote.get_ref().socket)
  }

  pub fn count_add(&mut self, key: &'static str, count_value: i64) {
    self.receive_metric(key, None, None, MetricData::Count(count_value));
  }

  pub fn set_gauge(&mut self, key: &'static str, gauge_value: usize) {
    self.receive_metric(key, None, None, MetricData::Gauge(gauge_value));
  }

  pub fn gauge_add(&mut self, key: &'static str, gauge_value: i64) {
    self.receive_metric(key, None, None, MetricData::GaugeAdd(gauge_value));
  }

  pub fn writable(&mut self) {
    if let Some(ref mut net) = self.network.as_mut() {
      net.writable();
    }
  }

  pub fn send_data(&mut self) {
    if let Some(ref mut net) = self.network.as_mut() {
      net.send_data();
    }
  }

  pub fn dump_metrics_data(&mut self) -> MetricsData {
    self.local.dump_metrics_data()
  }

  pub fn dump_process_data(&mut self) -> BTreeMap<String, FilteredData> {
    self.local.dump_process_data()
  }
}

impl Subscriber for Aggregator {
  fn receive_metric(&mut self, label: &'static str, app_id: Option<&str>, backend_id: Option<&str>, metric: MetricData) {
    if let Some(ref mut net) = self.network.as_mut() {
      net.receive_metric(label, app_id, backend_id, metric.clone());
    }
    self.local.receive_metric(label, app_id, backend_id, metric.clone());
  }
}

#[derive(Debug,Clone,PartialEq)]
pub struct MetricLine {
  label:      &'static str,
  app_id:     Option<String>,
  backend_id: Option<String>,
  /// in milliseconds
  duration:   usize,
}

pub struct MetricSocket {
  pub addr:   SocketAddr,
  pub socket: UdpSocket,
}

impl Write for MetricSocket {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    self.socket.send_to(buf, &self.addr)
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

pub fn udp_bind() -> UdpSocket {
  UdpSocket::bind(&("0.0.0.0:0".parse().unwrap())).expect("could not parse address")
}

#[macro_export]
macro_rules! count (
  ($key:expr, $value: expr) => {
    let v = $value;
    $crate::network::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).count_add($key, v);
    });
  }
);

#[macro_export]
macro_rules! incr (
  ($key:expr) => (count!($key, 1);)
);

#[macro_export]
macro_rules! decr (
  ($key:expr) => (count!($key, -1);)
);

#[macro_export]
macro_rules! gauge (
  ($key:expr, $value: expr) => {
    let v = $value;
    $crate::network::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).set_gauge($key, v);
    });
  }
);

#[macro_export]
macro_rules! gauge_add (
  ($key:expr, $value: expr) => {
    let v = $value;
    $crate::network::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).gauge_add($key, v);
    });
  }
);

#[macro_export]
macro_rules! time (
  ($key:expr, $value: expr) => {
    use std::time::Instant;
    use $crate::network::metrics::{MetricData,Subscriber};
    let v = $value;
    $crate::network::metrics::METRICS.with(|metrics| {
      let ref mut m = *metrics.borrow_mut();
      let app: &str = $app_id;

      m.receive_metric($key, None, None, MetricData::Time($value as usize));
    });
  };
  ($key:expr, $app_id:expr, $value: expr) => {
    use std::time::Instant;
    use $crate::network::metrics::{MetricData,Subscriber};
    let v = $value;
    $crate::network::metrics::METRICS.with(|metrics| {
      let ref mut m = *metrics.borrow_mut();
      let app: &str = $app_id;

      m.receive_metric($key, Some(app), None, MetricData::Time($value as usize));
    });
  }
);

#[macro_export]
macro_rules! record_backend_metrics (
  ($app_id:expr, $backend_id:expr, $response_time: expr, $bin: expr, $bout: expr) => {
    use std::time::Instant;
    use $crate::network::metrics::{MetricData,Subscriber};
    $crate::network::metrics::METRICS.with(|metrics| {
      let ref mut m = *metrics.borrow_mut();
      let app_id: &str = $app_id.as_str();
      let backend_id: &str = $backend_id;

      m.receive_metric("bin", Some(app_id), Some(backend_id), MetricData::Count($bin as i64));
      m.receive_metric("bout", Some(app_id), Some(backend_id), MetricData::Count($bout as i64));
      m.receive_metric("response_time", Some(app_id), Some(backend_id), MetricData::Time($response_time as usize));
    });
  }
);

<commit_msg>rename bin and bout to bytes_in and bytes_out<commit_after>use std::str;
use std::thread;
use std::sync::Mutex;
use std::cell::RefCell;
use std::time::{Duration,Instant};
use std::iter::repeat;
use std::collections::BTreeMap;
use std::collections::VecDeque;
use std::fmt::Arguments;
use std::net::SocketAddr;
use mio::net::UdpSocket;
use std::io::{self,BufWriter,Write,Error,ErrorKind};
use nom::HexDisplay;
use hdrhistogram::Histogram;
use sozu_command::buffer::Buffer;
use sozu_command::messages::{FilteredData,MetricsData,Percentiles,BackendMetricsData,FilteredTimeSerie};

mod network_drain;
mod local_drain;

use self::network_drain::NetworkDrain;
use self::local_drain::LocalDrain;

thread_local! {
  pub static METRICS: RefCell<Aggregator> = RefCell::new(Aggregator::new(String::from("sozu")));
}

#[derive(Debug,Clone,PartialEq)]
pub enum MetricData {
  Gauge(usize),
  GaugeAdd(i64),
  Count(i64),
  Time(usize),
}

impl MetricData {
  fn is_time(&self) -> bool {
    match self {
      &MetricData::Time(_) => true,
      _ => false,
    }
  }

  fn update(&mut self, key: &'static str, m: MetricData) {
    match (self, m) {
      (&mut MetricData::Gauge(ref mut v1), MetricData::Gauge(v2)) => {
        *v1 = v2;
      },
      (&mut MetricData::Gauge(ref mut v1), MetricData::GaugeAdd(v2)) => {
        *v1 = (*v1 as i64 + v2) as usize;
      },
      (&mut MetricData::Count(ref mut v1), MetricData::Count(v2)) => {
        *v1 += v2;
      },
      (s,m) => panic!("tried to update metric {} of value {:?} with an incompatible metric: {:?}", key, s, m)
    }
  }
}

#[derive(Debug,Clone)]
pub struct StoredMetricData {
  last_sent: Instant,
  data:      MetricData,
}

impl StoredMetricData {
  pub fn new(last_sent: Instant, data: MetricData) -> StoredMetricData {
    StoredMetricData {
      last_sent: last_sent,
      data: if let MetricData::GaugeAdd(v) = data {
        MetricData::Gauge(v as usize)
      } else { data }
    }
  }
}

pub fn setup<H: AsRef<str>, O: Into<String>>(host: H, port: u16, origin: O, use_tagged_metrics: bool) {
  use std::net::ToSocketAddrs;
  let metrics_socket = udp_bind();

  debug!("setting up metrics: local address = {:#?}", metrics_socket.local_addr());
  let metrics_host   = (host.as_ref(), port).to_socket_addrs().expect("could not parse address").next().expect("could not get first address");

  METRICS.with(|metrics| {
    (*metrics.borrow_mut()).set_up_remote(metrics_socket, metrics_host);
    (*metrics.borrow_mut()).set_up_origin(origin.into());
    (*metrics.borrow_mut()).set_up_tagged_metrics(use_tagged_metrics);
  });
}

pub trait Subscriber {
  fn receive_metric(&mut self, label: &'static str, app_id: Option<&str>, backend_id: Option<&str>, metric: MetricData);
}

pub struct Aggregator {
  prefix:  String,
  network: Option<NetworkDrain>,
  local:   LocalDrain,
}

impl Aggregator {
  pub fn new(prefix: String) -> Aggregator {
    Aggregator {
      prefix: prefix.clone(),
      network: None,
      local: LocalDrain::new(prefix),
    }
  }

  pub fn set_up_remote(&mut self, socket: UdpSocket, addr: SocketAddr) {
    self.network = Some(NetworkDrain::new(self.prefix.clone(), socket, addr));
  }

  pub fn set_up_origin(&mut self, origin: String) {
    self.network.as_mut().map(|n| n.origin = origin);
  }

  pub fn set_up_tagged_metrics(&mut self, tagged: bool) {
    self.network.as_mut().map(|n| n.use_tagged_metrics = tagged);
  }

  pub fn socket(&self) -> Option<&UdpSocket> {
    self.network.as_ref().map(|n| &n.remote.get_ref().socket)
  }

  pub fn count_add(&mut self, key: &'static str, count_value: i64) {
    self.receive_metric(key, None, None, MetricData::Count(count_value));
  }

  pub fn set_gauge(&mut self, key: &'static str, gauge_value: usize) {
    self.receive_metric(key, None, None, MetricData::Gauge(gauge_value));
  }

  pub fn gauge_add(&mut self, key: &'static str, gauge_value: i64) {
    self.receive_metric(key, None, None, MetricData::GaugeAdd(gauge_value));
  }

  pub fn writable(&mut self) {
    if let Some(ref mut net) = self.network.as_mut() {
      net.writable();
    }
  }

  pub fn send_data(&mut self) {
    if let Some(ref mut net) = self.network.as_mut() {
      net.send_data();
    }
  }

  pub fn dump_metrics_data(&mut self) -> MetricsData {
    self.local.dump_metrics_data()
  }

  pub fn dump_process_data(&mut self) -> BTreeMap<String, FilteredData> {
    self.local.dump_process_data()
  }
}

impl Subscriber for Aggregator {
  fn receive_metric(&mut self, label: &'static str, app_id: Option<&str>, backend_id: Option<&str>, metric: MetricData) {
    if let Some(ref mut net) = self.network.as_mut() {
      net.receive_metric(label, app_id, backend_id, metric.clone());
    }
    self.local.receive_metric(label, app_id, backend_id, metric.clone());
  }
}

#[derive(Debug,Clone,PartialEq)]
pub struct MetricLine {
  label:      &'static str,
  app_id:     Option<String>,
  backend_id: Option<String>,
  /// in milliseconds
  duration:   usize,
}

pub struct MetricSocket {
  pub addr:   SocketAddr,
  pub socket: UdpSocket,
}

impl Write for MetricSocket {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    self.socket.send_to(buf, &self.addr)
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

pub fn udp_bind() -> UdpSocket {
  UdpSocket::bind(&("0.0.0.0:0".parse().unwrap())).expect("could not parse address")
}

#[macro_export]
macro_rules! count (
  ($key:expr, $value: expr) => {
    let v = $value;
    $crate::network::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).count_add($key, v);
    });
  }
);

#[macro_export]
macro_rules! incr (
  ($key:expr) => (count!($key, 1);)
);

#[macro_export]
macro_rules! decr (
  ($key:expr) => (count!($key, -1);)
);

#[macro_export]
macro_rules! gauge (
  ($key:expr, $value: expr) => {
    let v = $value;
    $crate::network::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).set_gauge($key, v);
    });
  }
);

#[macro_export]
macro_rules! gauge_add (
  ($key:expr, $value: expr) => {
    let v = $value;
    $crate::network::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).gauge_add($key, v);
    });
  }
);

#[macro_export]
macro_rules! time (
  ($key:expr, $value: expr) => {
    use std::time::Instant;
    use $crate::network::metrics::{MetricData,Subscriber};
    let v = $value;
    $crate::network::metrics::METRICS.with(|metrics| {
      let ref mut m = *metrics.borrow_mut();
      let app: &str = $app_id;

      m.receive_metric($key, None, None, MetricData::Time($value as usize));
    });
  };
  ($key:expr, $app_id:expr, $value: expr) => {
    use std::time::Instant;
    use $crate::network::metrics::{MetricData,Subscriber};
    let v = $value;
    $crate::network::metrics::METRICS.with(|metrics| {
      let ref mut m = *metrics.borrow_mut();
      let app: &str = $app_id;

      m.receive_metric($key, Some(app), None, MetricData::Time($value as usize));
    });
  }
);

#[macro_export]
macro_rules! record_backend_metrics (
  ($app_id:expr, $backend_id:expr, $response_time: expr, $bin: expr, $bout: expr) => {
    use std::time::Instant;
    use $crate::network::metrics::{MetricData,Subscriber};
    $crate::network::metrics::METRICS.with(|metrics| {
      let ref mut m = *metrics.borrow_mut();
      let app_id: &str = $app_id.as_str();
      let backend_id: &str = $backend_id;

      m.receive_metric("bytes_in", Some(app_id), Some(backend_id), MetricData::Count($bin as i64));
      m.receive_metric("bytes_out", Some(app_id), Some(backend_id), MetricData::Count($bout as i64));
      m.receive_metric("response_time", Some(app_id), Some(backend_id), MetricData::Time($response_time as usize));
    });
  }
);

<|endoftext|>


<commit_before>use std::thread;
use std::process;
use std::time::Instant;
use std::sync::mpsc::{self, TryRecvError};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

use fps_clock::FpsClock;
use piston_window::{
    PistonWindow,
    WindowSettings,
    math,
};

use renderer::{Renderer, DrawingCommand};
use animation::{Animation, MoveAnimation, RotateAnimation, AnimationStatus};
use state::{TurtleState, DrawingState, Path, Pen};
use radians::{self, Radians};
use {Speed, Distance, Event, color};

use self::DrawingCommand::*;

/// Types that will be shared with another thread
pub type Shared<T> = Arc<RwLock<T>>;
/// Alias to help make the types more understandable without exposing as many implementation details
pub type ReadOnlyRef<'a, T> = RwLockReadGuard<'a, T>;
pub type MutableRef<'a, T> = RwLockWriteGuard<'a, T>;

/// A structure that provides read-only access to shared state
pub struct ReadOnly {
    turtle: Shared<TurtleState>,
    drawing: Shared<DrawingState>,
    /// A temporary path for use during animations
    temporary_path: Shared<Option<Path>>,
}

impl ReadOnly {
    pub fn turtle(&self) -> ReadOnlyRef<TurtleState> {
        self.turtle.read().expect("bug: Lock was poisoned")
    }

    pub fn drawing(&self) -> ReadOnlyRef<DrawingState> {
        self.drawing.read().expect("bug: Lock was poisoned")
    }

    pub fn temporary_path(&self) -> ReadOnlyRef<Option<Path>> {
        self.temporary_path.read().expect("bug: Lock was poisoned")
    }
}

pub struct TurtleWindow {
    thread_handle: Option<thread::JoinHandle<()>>,
    /// Channel for sending drawing commands to the renderer thread
    drawing_channel: mpsc::Sender<DrawingCommand>,
    /// Channel for receiving events from the rendering thread
    events_channel: mpsc::Receiver<Event>,

    turtle: Shared<TurtleState>,
    drawing: Shared<DrawingState>,
    /// A temporary path for use during animations
    temporary_path: Shared<Option<Path>>,
}

impl TurtleWindow {
    pub fn new() -> TurtleWindow {
        let (drawing_tx, drawing_rx) = mpsc::channel();
        let (events_tx, events_rx) = mpsc::channel();

        let mut turtle_window = Self {
            thread_handle: None,
            drawing_channel: drawing_tx,
            events_channel: events_rx,
            turtle: Arc::new(RwLock::new(TurtleState {
                position: [0., 0.],
                heading: Radians::from_degrees_value(90.),
                speed: Speed::Five,
                visible: true,
            })),
            drawing: Arc::new(RwLock::new(DrawingState {
                pen: Pen {
                    enabled: true,
                    thickness: 1.,
                    color: color::BLACK,
                },
                fill_color: color::BLACK,
                background: color::WHITE,
            })),
            temporary_path: Arc::new(RwLock::new(None)),
        };

        let read_only = turtle_window.read_only();
        let handle = thread::spawn(move || {
            let mut window: PistonWindow = WindowSettings::new(
                "Turtle", [800, 600]
            ).exit_on_esc(true).build().unwrap();

            Renderer::new().run(&mut window, drawing_rx, events_tx, read_only);
        });

        turtle_window.thread_handle = Some(handle);
        turtle_window
    }

    /// Provide a read-only version of the state
    pub fn read_only(&self) -> ReadOnly {
        ReadOnly {
            turtle: self.turtle.clone(),
            drawing: self.drawing.clone(),
            temporary_path: self.temporary_path.clone(),
        }
    }

    /// Provides read-only access to the turtle state
    pub fn turtle(&self) -> ReadOnlyRef<TurtleState> {
        self.turtle.read().expect("bug: Lock was poisoned")
    }

    /// Provides mutable access to the turtle state
    pub fn turtle_mut(&mut self) -> MutableRef<TurtleState> {
        self.turtle.write().expect("bug: Lock was poisoned")
    }

    /// Provides read-only access to the drawing
    pub fn drawing(&self) -> ReadOnlyRef<DrawingState> {
        self.drawing.read().expect("bug: Lock was poisoned")
    }

    /// Provides mutable access to the drawing
    pub fn drawing_mut(&mut self) -> MutableRef<DrawingState> {
        self.drawing.write().expect("bug: Lock was poisoned")
    }

    fn set_temporary_path(&mut self, path: Option<Path>) {
        let mut temp = self.temporary_path.write().expect("bug: Lock was poisoned");
        *temp = path;
    }

    /// See [`Turtle::poll_event()`](struct.Turtle.html#method.poll_event).
    pub fn poll_event(&mut self) -> Option<Event> {
        match self.events_channel.try_recv() {
            Ok(event) => Some(event),
            Err(TryRecvError::Empty) => None, // Do nothing
            // The window has been closed
            Err(TryRecvError::Disconnected) => process::exit(0), // Quit
        }
    }

    /// Begin filling the shape drawn by the turtle's movements.
    pub fn begin_fill(&mut self) {
        let fill_color = self.drawing().fill_color;
        self.send_drawing_command(BeginFill(fill_color));
    }

    /// Stop filling the current shape
    pub fn end_fill(&mut self) {
        self.send_drawing_command(EndFill);
    }

    /// Move the turtle forward by the given distance. To move backwards, use a negative distance.
    ///
    /// The turtle's motion will be animated based on the speed
    pub fn forward(&mut self, distance: Distance) {
        if distance == 0. {
            return;
        }

        let TurtleState {position: start, heading, speed, ..} = *self.turtle();
        let x = distance * heading.cos();
        let y = distance * heading.sin();
        let end = math::add(start, [x, y]);

        let speed = speed.to_absolute(); // px per second
        let total_millis = distance / speed * 1000.;

        let animation = MoveAnimation {
            path: Path {
                start,
                end,
                pen: self.drawing().pen.clone(),
            },
            timer: Instant::now(),
            total_millis,
        };

        self.play_animation(animation);
    }

    /// Rotate the turtle in place by the given angle in the given direction of rotation
    pub fn rotate(&mut self, angle: Radians, clockwise: bool) {
        if angle == radians::ZERO {
            return;
        }

        let TurtleState {heading, speed, ..} = *self.turtle();
        let speed = speed.to_rotation(); // radians per second
        let total_millis = angle / speed * 1000.;
        let total_millis = total_millis.to_radians();

        let animation = RotateAnimation {
            start: heading,
            delta_angle: angle,
            clockwise,
            timer: Instant::now(),
            total_millis,
        };

        self.play_animation(animation);
    }

    fn play_animation<A: Animation>(&mut self, animation: A) {
        // We only limit the framerate at all to be respectful of the user's CPU. If the framerate
        // is too small, every small movement (say forward(1) or right(1)) will take too long.
        // We use a huge framerate so we can sleep occasionally for longer animations but still
        // finish smaller ones in a reasonable amount of time.
        let mut fps = FpsClock::new(600);
        loop {
            // We want to keep the lock for as little time as possible
            let status = {
                let mut turtle = self.turtle_mut();
                animation.advance(&mut *turtle)
            };
            match status {
                AnimationStatus::Running(path) => self.set_temporary_path(path),
                AnimationStatus::Complete(path) => {
                    if let Some(path) = path {
                        self.set_temporary_path(None);
                        self.send_drawing_command(StorePath(path));
                    }

                    break;
                },
            }

            fps.tick();
        }
    }

    #[inline]
    fn send_drawing_command(&mut self, command: DrawingCommand) {
        self.drawing_channel.send(command).unwrap_or_else(|_| {
            // The channel is closed which means the window was closed
            // quit immediately
            process::exit(0);
        });
    }
}

impl Drop for TurtleWindow {
    fn drop(&mut self) {
        if let Some(handle) = self.thread_handle.take() {
            handle.join().unwrap();
        }
    }
}
<commit_msg>Fixed bug that was preventing backwards animations from working<commit_after>use std::thread;
use std::process;
use std::time::Instant;
use std::sync::mpsc::{self, TryRecvError};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

use fps_clock::FpsClock;
use piston_window::{
    PistonWindow,
    WindowSettings,
    math,
};

use renderer::{Renderer, DrawingCommand};
use animation::{Animation, MoveAnimation, RotateAnimation, AnimationStatus};
use state::{TurtleState, DrawingState, Path, Pen};
use radians::{self, Radians};
use {Speed, Distance, Event, color};

use self::DrawingCommand::*;

/// Types that will be shared with another thread
pub type Shared<T> = Arc<RwLock<T>>;
/// Alias to help make the types more understandable without exposing as many implementation details
pub type ReadOnlyRef<'a, T> = RwLockReadGuard<'a, T>;
pub type MutableRef<'a, T> = RwLockWriteGuard<'a, T>;

/// A structure that provides read-only access to shared state
pub struct ReadOnly {
    turtle: Shared<TurtleState>,
    drawing: Shared<DrawingState>,
    /// A temporary path for use during animations
    temporary_path: Shared<Option<Path>>,
}

impl ReadOnly {
    pub fn turtle(&self) -> ReadOnlyRef<TurtleState> {
        self.turtle.read().expect("bug: Lock was poisoned")
    }

    pub fn drawing(&self) -> ReadOnlyRef<DrawingState> {
        self.drawing.read().expect("bug: Lock was poisoned")
    }

    pub fn temporary_path(&self) -> ReadOnlyRef<Option<Path>> {
        self.temporary_path.read().expect("bug: Lock was poisoned")
    }
}

pub struct TurtleWindow {
    thread_handle: Option<thread::JoinHandle<()>>,
    /// Channel for sending drawing commands to the renderer thread
    drawing_channel: mpsc::Sender<DrawingCommand>,
    /// Channel for receiving events from the rendering thread
    events_channel: mpsc::Receiver<Event>,

    turtle: Shared<TurtleState>,
    drawing: Shared<DrawingState>,
    /// A temporary path for use during animations
    temporary_path: Shared<Option<Path>>,
}

impl TurtleWindow {
    pub fn new() -> TurtleWindow {
        let (drawing_tx, drawing_rx) = mpsc::channel();
        let (events_tx, events_rx) = mpsc::channel();

        let mut turtle_window = Self {
            thread_handle: None,
            drawing_channel: drawing_tx,
            events_channel: events_rx,
            turtle: Arc::new(RwLock::new(TurtleState {
                position: [0., 0.],
                heading: Radians::from_degrees_value(90.),
                speed: Speed::Five,
                visible: true,
            })),
            drawing: Arc::new(RwLock::new(DrawingState {
                pen: Pen {
                    enabled: true,
                    thickness: 1.,
                    color: color::BLACK,
                },
                fill_color: color::BLACK,
                background: color::WHITE,
            })),
            temporary_path: Arc::new(RwLock::new(None)),
        };

        let read_only = turtle_window.read_only();
        let handle = thread::spawn(move || {
            let mut window: PistonWindow = WindowSettings::new(
                "Turtle", [800, 600]
            ).exit_on_esc(true).build().unwrap();

            Renderer::new().run(&mut window, drawing_rx, events_tx, read_only);
        });

        turtle_window.thread_handle = Some(handle);
        turtle_window
    }

    /// Provide a read-only version of the state
    pub fn read_only(&self) -> ReadOnly {
        ReadOnly {
            turtle: self.turtle.clone(),
            drawing: self.drawing.clone(),
            temporary_path: self.temporary_path.clone(),
        }
    }

    /// Provides read-only access to the turtle state
    pub fn turtle(&self) -> ReadOnlyRef<TurtleState> {
        self.turtle.read().expect("bug: Lock was poisoned")
    }

    /// Provides mutable access to the turtle state
    pub fn turtle_mut(&mut self) -> MutableRef<TurtleState> {
        self.turtle.write().expect("bug: Lock was poisoned")
    }

    /// Provides read-only access to the drawing
    pub fn drawing(&self) -> ReadOnlyRef<DrawingState> {
        self.drawing.read().expect("bug: Lock was poisoned")
    }

    /// Provides mutable access to the drawing
    pub fn drawing_mut(&mut self) -> MutableRef<DrawingState> {
        self.drawing.write().expect("bug: Lock was poisoned")
    }

    fn set_temporary_path(&mut self, path: Option<Path>) {
        let mut temp = self.temporary_path.write().expect("bug: Lock was poisoned");
        *temp = path;
    }

    /// See [`Turtle::poll_event()`](struct.Turtle.html#method.poll_event).
    pub fn poll_event(&mut self) -> Option<Event> {
        match self.events_channel.try_recv() {
            Ok(event) => Some(event),
            Err(TryRecvError::Empty) => None, // Do nothing
            // The window has been closed
            Err(TryRecvError::Disconnected) => process::exit(0), // Quit
        }
    }

    /// Begin filling the shape drawn by the turtle's movements.
    pub fn begin_fill(&mut self) {
        let fill_color = self.drawing().fill_color;
        self.send_drawing_command(BeginFill(fill_color));
    }

    /// Stop filling the current shape
    pub fn end_fill(&mut self) {
        self.send_drawing_command(EndFill);
    }

    /// Move the turtle forward by the given distance. To move backwards, use a negative distance.
    ///
    /// The turtle's motion will be animated based on the speed
    pub fn forward(&mut self, distance: Distance) {
        if distance == 0. {
            return;
        }

        let TurtleState {position: start, heading, speed, ..} = *self.turtle();
        let x = distance * heading.cos();
        let y = distance * heading.sin();
        let end = math::add(start, [x, y]);

        let speed = speed.to_absolute(); // px per second
        let total_millis = (distance / speed * 1000.).abs();

        let animation = MoveAnimation {
            path: Path {
                start,
                end,
                pen: self.drawing().pen.clone(),
            },
            timer: Instant::now(),
            total_millis,
        };

        self.play_animation(animation);
    }

    /// Rotate the turtle in place by the given angle in the given direction of rotation
    pub fn rotate(&mut self, angle: Radians, clockwise: bool) {
        if angle == radians::ZERO {
            return;
        }

        let TurtleState {heading, speed, ..} = *self.turtle();
        let speed = speed.to_rotation(); // radians per second
        let total_millis = angle / speed * 1000.;
        let total_millis = total_millis.to_radians();

        let animation = RotateAnimation {
            start: heading,
            delta_angle: angle,
            clockwise,
            timer: Instant::now(),
            total_millis,
        };

        self.play_animation(animation);
    }

    fn play_animation<A: Animation>(&mut self, animation: A) {
        // We only limit the framerate at all to be respectful of the user's CPU. If the framerate
        // is too small, every small movement (say forward(1) or right(1)) will take too long.
        // We use a huge framerate so we can sleep occasionally for longer animations but still
        // finish smaller ones in a reasonable amount of time.
        let mut fps = FpsClock::new(600);
        loop {
            // We want to keep the lock for as little time as possible
            let status = {
                let mut turtle = self.turtle_mut();
                animation.advance(&mut *turtle)
            };
            match status {
                AnimationStatus::Running(path) => self.set_temporary_path(path),
                AnimationStatus::Complete(path) => {
                    if let Some(path) = path {
                        self.set_temporary_path(None);
                        self.send_drawing_command(StorePath(path));
                    }

                    break;
                },
            }

            fps.tick();
        }
    }

    #[inline]
    fn send_drawing_command(&mut self, command: DrawingCommand) {
        self.drawing_channel.send(command).unwrap_or_else(|_| {
            // The channel is closed which means the window was closed
            // quit immediately
            process::exit(0);
        });
    }
}

impl Drop for TurtleWindow {
    fn drop(&mut self) {
        if let Some(handle) = self.thread_handle.take() {
            handle.join().unwrap();
        }
    }
}
<|endoftext|>