<commit_before>use super::{contains_return, BIND_INSTEAD_OF_MAP};
use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_with_macro_callsite};
use clippy_utils::ty::match_type;
use clippy_utils::{in_macro, match_qpath, method_calls, paths, remove_blocks, visitors::find_all_ret_expressions};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::Span;

pub(crate) struct OptionAndThenSome;

impl BindInsteadOfMap for OptionAndThenSome {
    const TYPE_NAME: &'static str = "Option";
    const TYPE_QPATH: &'static [&'static str] = &paths::OPTION;

    const BAD_METHOD_NAME: &'static str = "and_then";
    const BAD_VARIANT_NAME: &'static str = "Some";
    const BAD_VARIANT_QPATH: &'static [&'static str] = &paths::OPTION_SOME;

    const GOOD_METHOD_NAME: &'static str = "map";
}

pub(crate) struct ResultAndThenOk;

impl BindInsteadOfMap for ResultAndThenOk {
    const TYPE_NAME: &'static str = "Result";
    const TYPE_QPATH: &'static [&'static str] = &paths::RESULT;

    const BAD_METHOD_NAME: &'static str = "and_then";
    const BAD_VARIANT_NAME: &'static str = "Ok";
    const BAD_VARIANT_QPATH: &'static [&'static str] = &paths::RESULT_OK;

    const GOOD_METHOD_NAME: &'static str = "map";
}

pub(crate) struct ResultOrElseErrInfo;

impl BindInsteadOfMap for ResultOrElseErrInfo {
    const TYPE_NAME: &'static str = "Result";
    const TYPE_QPATH: &'static [&'static str] = &paths::RESULT;

    const BAD_METHOD_NAME: &'static str = "or_else";
    const BAD_VARIANT_NAME: &'static str = "Err";
    const BAD_VARIANT_QPATH: &'static [&'static str] = &paths::RESULT_ERR;

    const GOOD_METHOD_NAME: &'static str = "map_err";
}

pub(crate) trait BindInsteadOfMap {
    const TYPE_NAME: &'static str;
    const TYPE_QPATH: &'static [&'static str];

    const BAD_METHOD_NAME: &'static str;
    const BAD_VARIANT_NAME: &'static str;
    const BAD_VARIANT_QPATH: &'static [&'static str];

    const GOOD_METHOD_NAME: &'static str;

    fn no_op_msg() -> String {
        format!(
            "using `{}.{}({})`, which is a no-op",
            Self::TYPE_NAME,
            Self::BAD_METHOD_NAME,
            Self::BAD_VARIANT_NAME
        )
    }

    fn lint_msg() -> String {
        format!(
            "using `{}.{}(|x| {}(y))`, which is more succinctly expressed as `{}(|x| y)`",
            Self::TYPE_NAME,
            Self::BAD_METHOD_NAME,
            Self::BAD_VARIANT_NAME,
            Self::GOOD_METHOD_NAME
        )
    }

    fn lint_closure_autofixable(
        cx: &LateContext<'_>,
        expr: &hir::Expr<'_>,
        recv: &hir::Expr<'_>,
        closure_expr: &hir::Expr<'_>,
        closure_args_span: Span,
    ) -> bool {
        if_chain! {
            if let hir::ExprKind::Call(ref some_expr, ref some_args) = closure_expr.kind;
            if let hir::ExprKind::Path(ref qpath) = some_expr.kind;
            if match_qpath(qpath, Self::BAD_VARIANT_QPATH);
            if some_args.len() == 1;
            then {
                let inner_expr = &some_args[0];

                if contains_return(inner_expr) {
                    return false;
                }

                let some_inner_snip = if inner_expr.span.from_expansion() {
                    snippet_with_macro_callsite(cx, inner_expr.span, "_")
                } else {
                    snippet(cx, inner_expr.span, "_")
                };

                let closure_args_snip = snippet(cx, closure_args_span, "..");
                let option_snip = snippet(cx, recv.span, "..");
                let note = format!("{}.{}({} {})", option_snip, Self::GOOD_METHOD_NAME, closure_args_snip, some_inner_snip);
                span_lint_and_sugg(
                    cx,
                    BIND_INSTEAD_OF_MAP,
                    expr.span,
                    Self::lint_msg().as_ref(),
                    "try this",
                    note,
                    Applicability::MachineApplicable,
                );
                true
            } else {
                false
            }
        }
    }

    fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) -> bool {
        let mut suggs = Vec::new();
        let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
            if_chain! {
                if !in_macro(ret_expr.span);
                if let hir::ExprKind::Call(ref func_path, ref args) = ret_expr.kind;
                if let hir::ExprKind::Path(ref qpath) = func_path.kind;
                if match_qpath(qpath, Self::BAD_VARIANT_QPATH);
                if args.len() == 1;
                if !contains_return(&args[0]);
                then {
                    suggs.push((ret_expr.span, args[0].span.source_callsite()));
                    true
                } else {
                    false
                }
            }
        });

        if can_sugg {
            span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, Self::lint_msg().as_ref(), |diag| {
                multispan_sugg_with_applicability(
                    diag,
                    "try this",
                    Applicability::MachineApplicable,
                    std::iter::once((*method_calls(expr, 1).2.get(0).unwrap(), Self::GOOD_METHOD_NAME.into())).chain(
                        suggs
                            .into_iter()
                            .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
                    ),
                )
            });
        }
        can_sugg
    }

    /// Lint use of `_.and_then(|x| Some(y))` for `Option`s
    fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool {
        if !match_type(cx, cx.typeck_results().expr_ty(recv), Self::TYPE_QPATH) {
            return false;
        }

        match arg.kind {
            hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => {
                let closure_body = cx.tcx.hir().body(body_id);
                let closure_expr = remove_blocks(&closure_body.value);

                if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, closure_args_span) {
                    true
                } else {
                    Self::lint_closure(cx, expr, closure_expr)
                }
            },
            // `_.and_then(Some)` case, which is no-op.
            hir::ExprKind::Path(ref qpath) if match_qpath(qpath, Self::BAD_VARIANT_QPATH) => {
                span_lint_and_sugg(
                    cx,
                    BIND_INSTEAD_OF_MAP,
                    expr.span,
                    Self::no_op_msg().as_ref(),
                    "use the expression directly",
                    snippet(cx, recv.span, "..").into(),
                    Applicability::MachineApplicable,
                );
                true
            },
            _ => false,
        }
    }
}
<commit_msg>Auto merge of #7016 - camsteffen:bind-map-paths, r=Manishearth<commit_after>use super::{contains_return, BIND_INSTEAD_OF_MAP};
use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_with_macro_callsite};
use clippy_utils::{in_macro, remove_blocks, visitors::find_all_ret_expressions};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::{LangItem, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty::DefIdTree;
use rustc_span::Span;

pub(crate) struct OptionAndThenSome;

impl BindInsteadOfMap for OptionAndThenSome {
    const VARIANT_LANG_ITEM: LangItem = LangItem::OptionSome;
    const BAD_METHOD_NAME: &'static str = "and_then";
    const GOOD_METHOD_NAME: &'static str = "map";
}

pub(crate) struct ResultAndThenOk;

impl BindInsteadOfMap for ResultAndThenOk {
    const VARIANT_LANG_ITEM: LangItem = LangItem::ResultOk;
    const BAD_METHOD_NAME: &'static str = "and_then";
    const GOOD_METHOD_NAME: &'static str = "map";
}

pub(crate) struct ResultOrElseErrInfo;

impl BindInsteadOfMap for ResultOrElseErrInfo {
    const VARIANT_LANG_ITEM: LangItem = LangItem::ResultErr;
    const BAD_METHOD_NAME: &'static str = "or_else";
    const GOOD_METHOD_NAME: &'static str = "map_err";
}

pub(crate) trait BindInsteadOfMap {
    const VARIANT_LANG_ITEM: LangItem;
    const BAD_METHOD_NAME: &'static str;
    const GOOD_METHOD_NAME: &'static str;

    fn no_op_msg(cx: &LateContext<'_>) -> Option<String> {
        let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
        let item_id = cx.tcx.parent(variant_id)?;
        Some(format!(
            "using `{}.{}({})`, which is a no-op",
            cx.tcx.item_name(item_id),
            Self::BAD_METHOD_NAME,
            cx.tcx.item_name(variant_id),
        ))
    }

    fn lint_msg(cx: &LateContext<'_>) -> Option<String> {
        let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
        let item_id = cx.tcx.parent(variant_id)?;
        Some(format!(
            "using `{}.{}(|x| {}(y))`, which is more succinctly expressed as `{}(|x| y)`",
            cx.tcx.item_name(item_id),
            Self::BAD_METHOD_NAME,
            cx.tcx.item_name(variant_id),
            Self::GOOD_METHOD_NAME
        ))
    }

    fn lint_closure_autofixable(
        cx: &LateContext<'_>,
        expr: &hir::Expr<'_>,
        recv: &hir::Expr<'_>,
        closure_expr: &hir::Expr<'_>,
        closure_args_span: Span,
    ) -> bool {
        if_chain! {
            if let hir::ExprKind::Call(ref some_expr, [inner_expr]) = closure_expr.kind;
            if let hir::ExprKind::Path(QPath::Resolved(_, path)) = some_expr.kind;
            if Self::is_variant(cx, path.res);
            if !contains_return(inner_expr);
            if let Some(msg) = Self::lint_msg(cx);
            then {
                let some_inner_snip = if inner_expr.span.from_expansion() {
                    snippet_with_macro_callsite(cx, inner_expr.span, "_")
                } else {
                    snippet(cx, inner_expr.span, "_")
                };

                let closure_args_snip = snippet(cx, closure_args_span, "..");
                let option_snip = snippet(cx, recv.span, "..");
                let note = format!("{}.{}({} {})", option_snip, Self::GOOD_METHOD_NAME, closure_args_snip, some_inner_snip);
                span_lint_and_sugg(
                    cx,
                    BIND_INSTEAD_OF_MAP,
                    expr.span,
                    &msg,
                    "try this",
                    note,
                    Applicability::MachineApplicable,
                );
                true
            } else {
                false
            }
        }
    }

    fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) -> bool {
        let mut suggs = Vec::new();
        let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
            if_chain! {
                if !in_macro(ret_expr.span);
                if let hir::ExprKind::Call(ref func_path, [arg]) = ret_expr.kind;
                if let hir::ExprKind::Path(QPath::Resolved(_, path)) = func_path.kind;
                if Self::is_variant(cx, path.res);
                if !contains_return(arg);
                then {
                    suggs.push((ret_expr.span, arg.span.source_callsite()));
                    true
                } else {
                    false
                }
            }
        });
        let (span, msg) = if_chain! {
            if can_sugg;
            if let hir::ExprKind::MethodCall(_, span, ..) = expr.kind;
            if let Some(msg) = Self::lint_msg(cx);
            then { (span, msg) } else { return false; }
        };
        span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, &msg, |diag| {
            multispan_sugg_with_applicability(
                diag,
                "try this",
                Applicability::MachineApplicable,
                std::iter::once((span, Self::GOOD_METHOD_NAME.into())).chain(
                    suggs
                        .into_iter()
                        .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
                ),
            )
        });
        true
    }

    /// Lint use of `_.and_then(|x| Some(y))` for `Option`s
    fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool {
        if_chain! {
            if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def();
            if let Ok(vid) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM);
            if Some(adt.did) == cx.tcx.parent(vid);
            then {} else { return false; }
        }

        match arg.kind {
            hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => {
                let closure_body = cx.tcx.hir().body(body_id);
                let closure_expr = remove_blocks(&closure_body.value);

                if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, closure_args_span) {
                    true
                } else {
                    Self::lint_closure(cx, expr, closure_expr)
                }
            },
            // `_.and_then(Some)` case, which is no-op.
            hir::ExprKind::Path(QPath::Resolved(_, path)) if Self::is_variant(cx, path.res) => {
                if let Some(msg) = Self::no_op_msg(cx) {
                    span_lint_and_sugg(
                        cx,
                        BIND_INSTEAD_OF_MAP,
                        expr.span,
                        &msg,
                        "use the expression directly",
                        snippet(cx, recv.span, "..").into(),
                        Applicability::MachineApplicable,
                    );
                }
                true
            },
            _ => false,
        }
    }

    fn is_variant(cx: &LateContext<'_>, res: Res) -> bool {
        if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
            if let Ok(variant_id) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM) {
                return cx.tcx.parent(id) == Some(variant_id);
            }
        }
        false
    }
}
<|endoftext|>


<commit_before>// This test case tests whether we can handle code bases that contain a high
// number of closures, something that needs special handling in the MingGW
// toolchain.
// See https://github.com/rust-lang/rust/issues/34793 for more information.

// Make sure we don't optimize anything away:
// compile-flags: -C no-prepopulate-passes -Cpasses=name-anon-globals

// Expand something exponentially
macro_rules! go_bacterial {
    ($mac:ident) => ($mac!());
    ($mac:ident 1 $($t:tt)*) => (
        go_bacterial!($mac $($t)*);
        go_bacterial!($mac $($t)*);
    )
}

macro_rules! mk_closure {
    () => ((move || {})())
}

macro_rules! mk_fn {
    () => {
        {
            fn function() {
                // Make 16 closures
                go_bacterial!(mk_closure 1 1 1 1);
            }
            let _ = function();
        }
    }
}

fn main() {
    // Make 2^12 functions, each containing 16 closures,
    // resulting in 2^16 closures overall.
    go_bacterial!(mk_fn 1 1 1 1  1 1 1 1  1 1 1 1);
}
<commit_msg>Turn down the myriad-closures test<commit_after>// This test case tests whether we can handle code bases that contain a high
// number of closures, something that needs special handling in the MingGW
// toolchain.
// See https://github.com/rust-lang/rust/issues/34793 for more information.

// Make sure we don't optimize anything away:
// compile-flags: -C no-prepopulate-passes -Cpasses=name-anon-globals

// Expand something exponentially
macro_rules! go_bacterial {
    ($mac:ident) => ($mac!());
    ($mac:ident 1 $($t:tt)*) => (
        go_bacterial!($mac $($t)*);
        go_bacterial!($mac $($t)*);
    )
}

macro_rules! mk_closure {
    () => ((move || {})())
}

macro_rules! mk_fn {
    () => {
        {
            fn function() {
                // Make 16 closures
                go_bacterial!(mk_closure 1 1 1 1);
            }
            let _ = function();
        }
    }
}

fn main() {
    // Make 2^8 functions, each containing 16 closures,
    // resulting in 2^12 closures overall.
    go_bacterial!(mk_fn 1 1 1 1  1 1 1 1);
}
<|endoftext|>


<commit_before>use super::*;
use redox::*;

/// The state of the editor
pub struct Editor {
    /// The current cursor
    pub current_cursor: u8,
    /// The cursors
    pub cursors: Vec<Cursor>,
    /// The text (document)
    pub text: VecDeque<VecDeque<char>>,
    /// The x coordinate of the scroll
    pub scroll_x: usize,
    /// The y coordinate of the scroll
    pub scroll_y: usize,
    /// The window
    pub window: Window,
    /// The key state
    pub key_state: KeyState,
    /// The status bar
    pub status_bar: StatusBar,
}

impl Editor {
    /// Create new default state editor
    pub fn new() -> Editor {

        let window = Window::new((rand() % 400 + 50) as isize,
                                 (rand() % 300 + 50) as isize,
                                 700,
                                 500,
                                 &"Sodium").unwrap();

        let mut editor = Editor {
            current_cursor: 0,
            cursors: Vec::new(),
            text: VecDeque::new(),
            scroll_x: 0,
            scroll_y: 0,
            window: *window,
            key_state: KeyState::new(),
            status_bar: StatusBar::new(),
        };

        editor.cursors.push(Cursor::new());
        editor.text.push_back(VecDeque::new());

        editor.redraw();
        loop {
            let inp = editor.next_inst();
            editor.exec(inp);
            editor.redraw();
            editor.status_bar.mode = editor.cursor().mode.to_string();
        }

        editor
    }
}

<commit_msg>Fix error<commit_after>use super::*;
use redox::*;

/// The state of the editor
pub struct Editor {
    /// The current cursor
    pub current_cursor: u8,
    /// The cursors
    pub cursors: Vec<Cursor>,
    /// The text (document)
    pub text: VecDeque<VecDeque<char>>,
    /// The x coordinate of the scroll
    pub scroll_x: usize,
    /// The y coordinate of the scroll
    pub scroll_y: usize,
    /// The window
    pub window: Window,
    /// The key state
    pub key_state: KeyState,
    /// The status bar
    pub status_bar: StatusBar,
}

impl Editor {
    /// Create new default state editor
    pub fn new() -> Editor {

        let window = Window::new((rand() % 400 + 50) as isize,
                                 (rand() % 300 + 50) as isize,
                                 700,
                                 500,
                                 &"Sodium").unwrap();

        let mut editor = Editor {
            current_cursor: 0,
            cursors: Vec::new(),
            text: VecDeque::new(),
            scroll_x: 0,
            scroll_y: 0,
            window: *window,
            key_state: KeyState::new(),
            status_bar: StatusBar::new(),
        };

        editor.cursors.push(Cursor::new());
        editor.text.push_back(VecDeque::new());

        editor.redraw();
        loop {
            let inp = editor.next_inst();
            editor.exec(inp);
            editor.redraw();
            editor.status_bar.mode = editor.cursor().mode.to_string();
        }

        editor
    }
    pub fn get_ln(&self, n: usize) -> &[char] {
        self.text[n].as_slices().0
    }
}

<|endoftext|>


<commit_before>use crate::stacked_borrows::Tag;
use crate::*;

use std::time::{Duration, SystemTime};

fn get_time() -> (Duration, i128) {
    let mut sign = 1;
    let duration = SystemTime::now()
        .duration_since(SystemTime::UNIX_EPOCH)
        .unwrap_or_else(|e| {
            sign = -1;
            e.duration()
        });
    (duration, sign)
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn clock_gettime(
        &mut self,
        clk_id_op: OpTy<'tcx, Tag>,
        tp_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        if !this.machine.communicate {
            throw_unsup_format!("`clock_gettime` not available when isolation is enabled")
        }

        let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
        if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        }

        let tp = this.force_ptr(this.read_scalar(tp_op)?.not_undef()?)?;

        let (duration, sign) = get_time();
        let tv_sec = sign * (duration.as_secs() as i128);
        let tv_nsec = duration.subsec_nanos() as i128;
        this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?;

        Ok(0)
    }

    fn gettimeofday(
        &mut self,
        tv_op: OpTy<'tcx, Tag>,
        tz_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        if !this.machine.communicate {
            throw_unsup_format!("`gettimeofday` not available when isolation is enabled")
        }
        // Using tz is obsolete and should always be null
        let tz = this.read_scalar(tz_op)?.not_undef()?;
        if !this.is_null(tz)? {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        }

        let tv = this.force_ptr(this.read_scalar(tv_op)?.not_undef()?)?;

        let (duration, sign) = get_time();
        let tv_sec = sign * (duration.as_secs() as i128);
        let tv_usec = duration.subsec_micros() as i128;

        this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?;

        Ok(0)
    }
}
<commit_msg>Fix sign when number of seconds is zero<commit_after>use crate::stacked_borrows::Tag;
use crate::*;

use std::time::{Duration, SystemTime};

fn get_time() -> (Duration, i128) {
    let mut sign = 1;
    let duration = SystemTime::now()
        .duration_since(SystemTime::UNIX_EPOCH)
        .unwrap_or_else(|e| {
            sign = -1;
            e.duration()
        });
    (duration, sign)
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    // Foreign function used by linux
    fn clock_gettime(
        &mut self,
        clk_id_op: OpTy<'tcx, Tag>,
        tp_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        if !this.machine.communicate {
            throw_unsup_format!("`clock_gettime` not available when isolation is enabled")
        }

        let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
        if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        }

        let tp = this.force_ptr(this.read_scalar(tp_op)?.not_undef()?)?;

        let (duration, sign) = get_time();
        let tv_sec = sign * (duration.as_secs() as i128);
        let mut tv_nsec = duration.subsec_nanos() as i128;
        // If the number of seconds is zero, we need to put the sign into the second's fraction.
        if tv_sec == 0 && sign < 0 {
            tv_nsec *= sign;
        }

        this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?;

        Ok(0)
    }
    // Foreign function used by generic unix
    fn gettimeofday(
        &mut self,
        tv_op: OpTy<'tcx, Tag>,
        tz_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        if !this.machine.communicate {
            throw_unsup_format!("`gettimeofday` not available when isolation is enabled")
        }
        // Using tz is obsolete and should always be null
        let tz = this.read_scalar(tz_op)?.not_undef()?;
        if !this.is_null(tz)? {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        }

        let tv = this.force_ptr(this.read_scalar(tv_op)?.not_undef()?)?;

        let (duration, sign) = get_time();
        let tv_sec = sign * (duration.as_secs() as i128);
        let mut tv_usec = duration.subsec_micros() as i128;
        // If the number of seconds is zero, we need to put the sign into the second's fraction.
        if tv_sec == 0 && sign < 0 {
            tv_usec *= sign;
        }

        this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?;

        Ok(0)
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fs;
use std::io::prelude::*;
use std::path::Path;

#[derive(Clone)]
#[derive(Debug)]
pub enum CellState
{
	Dead,
	Alive
}

pub struct Simulator {
	iteration_num: u32,
	height: usize,
	width: usize,
	output_dir: String,
	starting_states: Vec<Vec<CellState>>,
	current_iteration: u32,
}

impl<'a> Simulator {
	pub fn new(iteration_num: u32, output_dir: String,
		starting_states: Vec<Vec<CellState>>) -> Simulator {
		// Check input data
		if starting_states.len() < 1 {
			panic!("not enough rows");
		}
		let row_length = starting_states[0].len();
		for row in &starting_states {
			if row.len() != row_length {
				panic!("row lengths do not match");
			}
		}
		// Check input directory
		if !fs::metadata(&output_dir).is_ok() {
			match fs::create_dir_all(&output_dir) {
				Ok(_) => {},
				Err(e) => {
					panic!("output directory did not exist and cannot be created: {}",
						e.description());
				}
			}
		}
		// Assign struct
		Simulator {
			iteration_num: iteration_num,
			height: starting_states.len(),
			width: starting_states[0].len(),
			output_dir: output_dir,
			starting_states: starting_states,
			current_iteration: 0,
		}
	}

	pub fn run_simulation(&mut self) {
		// Set up first cells
		let mut current_states = self.create_initial_states();
		loop {
			// Create new states
			let mut new_states = Vec::new();
			for x in 0..self.height {
				let mut new_row = Vec::new();
				for y in 0..self.width {
					let cell = current_states[x][y].clone();
					let new_cell = cell.iterate(&current_states);
					new_row.push(new_cell);
				}
				new_states.push(new_row);
			}
			// Set current states
			current_states = new_states;
			// Output
			{
				let current_states = &current_states;
				self.output(current_states);
			}
			// Increment iteration
			self.current_iteration += 1;
			if self.current_iteration == self.iteration_num {
				break;
			}
		}
	}

	fn create_initial_states(&mut self) -> Vec<Vec<Cell>> {
		let mut states = Vec::new();
		for x in 0..self.starting_states.len() {
			let mut row = Vec::new();
			for y in 0..self.starting_states[x].len() {
				row.push(Cell {
					state: self.starting_states[x][y].clone(),
					row: x,
					col: y,
				});
			}
			states.push(row);
		}
		return states;
	}

	fn output(&mut self, current_states: &Vec<Vec<Cell>>) {
		let path = Path::new(&self.output_dir);
		let path = path.join(format!("{}.csv", self.current_iteration));
		let mut file = match fs::File::create(&path) {
			Err(why) => panic!("couldn't create {}: {}",
								path.display(), why.description()),
			Ok(file) => file,
		};
		for row in current_states {
			let mut row_str: String = row.iter().map(|c| match c.state {
				CellState::Dead => "0",
				CellState::Alive => "1",
			}).collect::<Vec<&str>>().join(",");
			row_str.push('\n');
			match file.write_all(row_str.as_bytes()) {
				Err(why) => {
					panic!("couldn't write to {}: {}", path.display(),
						   why.description())
				},
				Ok(_) => {},
			}
		}
	}
}

#[derive(Clone)]
struct Cell {
	state: CellState,
	row: usize,
	col: usize,
}

impl Cell {
	fn iterate(self, prev_state: &Vec<Vec<Cell>>) -> Cell {
		// TODO: write rules for Conways Game of Life
		return Cell {
			state: match self.state {
				CellState::Dead => CellState::Alive,
				CellState::Alive => CellState::Dead,
			},
			row: self.row,
			col: self.col,
		};
	}
}<commit_msg>Implemented Conways Game of Life rules<commit_after>use std::error::Error;
use std::fs;
use std::io::prelude::*;
use std::path::Path;

#[derive(Clone)]
#[derive(Debug)]
pub enum CellState
{
	Dead,
	Alive
}

pub struct Simulator {
	iteration_num: u32,
	height: usize,
	width: usize,
	output_dir: String,
	starting_states: Vec<Vec<CellState>>,
	current_iteration: u32,
}

impl<'a> Simulator {
	pub fn new(iteration_num: u32, output_dir: String,
		starting_states: Vec<Vec<CellState>>) -> Simulator {
		// Check input data
		if starting_states.len() < 1 {
			panic!("not enough rows");
		}
		let row_length = starting_states[0].len();
		for row in &starting_states {
			if row.len() != row_length {
				panic!("row lengths do not match");
			}
		}
		// Check input directory
		if !fs::metadata(&output_dir).is_ok() {
			match fs::create_dir_all(&output_dir) {
				Ok(_) => {},
				Err(e) => {
					panic!("output directory did not exist and cannot be created: {}",
						e.description());
				}
			}
		}
		// Assign struct
		Simulator {
			iteration_num: iteration_num,
			height: starting_states.len(),
			width: starting_states[0].len(),
			output_dir: output_dir,
			starting_states: starting_states,
			current_iteration: 0,
		}
	}

	pub fn run_simulation(&mut self) {
		// Set up first cells
		let mut current_states = self.create_initial_states();
		loop {
			// Create new states
			let mut new_states = Vec::new();
			for x in 0..self.height {
				let mut new_row = Vec::new();
				for y in 0..self.width {
					let cell = current_states[x][y].clone();
					let new_cell = cell.iterate(&current_states);
					new_row.push(new_cell);
				}
				new_states.push(new_row);
			}
			// Set current states
			current_states = new_states;
			// Output
			{
				let current_states = &current_states;
				self.output(current_states);
			}
			// Increment iteration
			self.current_iteration += 1;
			if self.current_iteration == self.iteration_num {
				break;
			}
		}
	}

	fn create_initial_states(&mut self) -> Vec<Vec<Cell>> {
		let mut states = Vec::new();
		for x in 0..self.starting_states.len() {
			let mut row = Vec::new();
			for y in 0..self.starting_states[x].len() {
				row.push(Cell {
					state: self.starting_states[x][y].clone(),
					row: x,
					col: y,
				});
			}
			states.push(row);
		}
		return states;
	}

	fn output(&mut self, current_states: &Vec<Vec<Cell>>) {
		let path = Path::new(&self.output_dir);
		let path = path.join(format!("{}.csv", self.current_iteration));
		let mut file = match fs::File::create(&path) {
			Err(why) => panic!("couldn't create {}: {}",
								path.display(), why.description()),
			Ok(file) => file,
		};
		for row in current_states {
			let mut row_str: String = row.iter().map(|c| match c.state {
				CellState::Dead => "0",
				CellState::Alive => "1",
			}).collect::<Vec<&str>>().join(",");
			row_str.push('\n');
			match file.write_all(row_str.as_bytes()) {
				Err(why) => {
					panic!("couldn't write to {}: {}", path.display(),
						   why.description())
				},
				Ok(_) => {},
			}
		}
	}
}

#[derive(Clone)]
struct Cell {
	state: CellState,
	row: usize,
	col: usize,
}

impl Cell {
	fn iterate(self, prev_state: &Vec<Vec<Cell>>) -> Cell {
		// TODO: write rules for Conways Game of Life
		let alive_neighbours = self.count_alive_neighbours(prev_state);
		return Cell {
			state: self.conways_rules(alive_neighbours),
			row: self.row,
			col: self.col,
		};
	}

	fn count_alive_neighbours(&self, prev_state: &Vec<Vec<Cell>>) -> usize {
		let mut alive_neighbours: usize = 0;
		for x in 0..3 {
			for y in 0..3 {
				if (self.row > 0) &&  (self.row + x < prev_state.len()) &&
					(self.col > 0) && (self.col + y < prev_state[0].len()) {
					let n_x: usize = self.row + x - 1;
					let n_y: usize = self.col + y - 1;
					alive_neighbours = match prev_state[n_x][n_y].state {
						CellState::Alive => alive_neighbours + 1,
						CellState::Dead => alive_neighbours
					}
				}
			}
		}
		return alive_neighbours;
	}

	fn conways_rules(&self, alive_neighbours: usize) -> CellState {
		match self.state {
			CellState::Alive => {
				if alive_neighbours < 2 || alive_neighbours > 3 {
					CellState::Dead
				} else {
				    CellState::Alive
				}
			},
			CellState::Dead => {
				if alive_neighbours == 3 {
					CellState::Alive
				} else {
				    CellState::Dead
				}
			}
		}
	}
}<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{convert::TryInto, fs::File, io::Write, path::Path};

use assert_cmd::Command;
use tempdir::TempDir;

static MAIN_RS: &str = include_str!("../../../demo/src/main.rs");
static INPUT_H: &str = include_str!("../../../demo/src/input.h");

#[test]
fn test_help() -> Result<(), Box<dyn std::error::Error>> {
    let mut cmd = Command::cargo_bin("autocxx-gen")?;
    cmd.arg("-h").assert().success();
    Ok(())
}

fn base_test<F>(tmp_dir: &TempDir, arg_modifier: F) -> Result<(), Box<dyn std::error::Error>>
where
    F: FnOnce(&mut Command),
{
    let demo_code_dir = tmp_dir.path().join("demo");
    std::fs::create_dir(&demo_code_dir).unwrap();
    write_to_file(&demo_code_dir, "input.h", INPUT_H.as_bytes());
    write_to_file(&demo_code_dir, "main.rs", MAIN_RS.as_bytes());
    let demo_rs = demo_code_dir.join("main.rs");
    let mut cmd = Command::cargo_bin("autocxx-gen")?;
    arg_modifier(&mut cmd);
    cmd.arg("--inc")
        .arg(demo_code_dir.to_str().unwrap())
        .arg(demo_rs)
        .arg("--outdir")
        .arg(tmp_dir.path().to_str().unwrap())
        .arg("--gen-cpp")
        .arg("--gen-rs-include")
        .assert()
        .success();
    assert_contentful(&tmp_dir, "gen0.cc");
    Ok(())
}

#[test]
fn test_gen() -> Result<(), Box<dyn std::error::Error>> {
    let tmp_dir = TempDir::new("example")?;
    base_test(&tmp_dir, |_| {})
}

#[test]
fn test_gen_fixed_num() -> Result<(), Box<dyn std::error::Error>> {
    let tmp_dir = TempDir::new("example")?;
    base_test(&tmp_dir, |cmd| {
        cmd.arg("--generate-exact")
            .arg("3")
            .arg("--fix-rs-include-name");
    })?;
    assert_contentful(&tmp_dir, "gen0.cc");
    assert_exists(&tmp_dir, "gen1.cc");
    assert_exists(&tmp_dir, "gen2.cc");
    assert_contentful(&tmp_dir, "gen0.include.rs");
    assert_exists(&tmp_dir, "gen1.include.rs");
    assert_exists(&tmp_dir, "gen2.include.rs");
    Ok(())
}

#[test]
fn test_gen_preprocess() -> Result<(), Box<dyn std::error::Error>> {
    let tmp_dir = TempDir::new("example")?;
    let prepro_path = tmp_dir.path().join("preprocessed.h");
    base_test(&tmp_dir, |cmd| {
        cmd.env("AUTOCXX_PREPROCESS", prepro_path.to_str().unwrap());
    })?;
    assert_contentful(&tmp_dir, "preprocessed.h");
    Ok(())
}

fn write_to_file(dir: &Path, filename: &str, content: &[u8]) {
    let path = dir.join(filename);
    let mut f = File::create(&path).expect("Unable to create file");
    f.write_all(content).expect("Unable to write file");
}

fn assert_contentful(outdir: &TempDir, fname: &str) {
    let p = outdir.path().join(fname);
    if !p.exists() {
        panic!("File {} didn't exist", p.to_string_lossy());
    }
    assert!(p.metadata().unwrap().len() > super::BLANK.len().try_into().unwrap());
}

fn assert_exists(outdir: &TempDir, fname: &str) {
    let p = outdir.path().join(fname);
    if !p.exists() {
        panic!("File {} didn't exist", p.to_string_lossy());
    }
}
<commit_msg>Add test for inclusion.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{convert::TryInto, fs::File, io::Write, path::Path};

use assert_cmd::Command;
use tempdir::TempDir;

static MAIN_RS: &str = include_str!("../../../demo/src/main.rs");
static INPUT_H: &str = include_str!("../../../demo/src/input.h");

#[test]
fn test_help() -> Result<(), Box<dyn std::error::Error>> {
    let mut cmd = Command::cargo_bin("autocxx-gen")?;
    cmd.arg("-h").assert().success();
    Ok(())
}

fn base_test<F>(tmp_dir: &TempDir, arg_modifier: F) -> Result<(), Box<dyn std::error::Error>>
where
    F: FnOnce(&mut Command),
{
    let demo_code_dir = tmp_dir.path().join("demo");
    std::fs::create_dir(&demo_code_dir).unwrap();
    write_to_file(&demo_code_dir, "input.h", INPUT_H.as_bytes());
    write_to_file(&demo_code_dir, "main.rs", MAIN_RS.as_bytes());
    let demo_rs = demo_code_dir.join("main.rs");
    let mut cmd = Command::cargo_bin("autocxx-gen")?;
    arg_modifier(&mut cmd);
    cmd.arg("--inc")
        .arg(demo_code_dir.to_str().unwrap())
        .arg(demo_rs)
        .arg("--outdir")
        .arg(tmp_dir.path().to_str().unwrap())
        .arg("--gen-cpp")
        .arg("--gen-rs-include")
        .assert()
        .success();
    assert_contentful(&tmp_dir, "gen0.cc");
    Ok(())
}

#[test]
fn test_gen() -> Result<(), Box<dyn std::error::Error>> {
    let tmp_dir = TempDir::new("example")?;
    base_test(&tmp_dir, |_| {})
}

#[test]
fn test_gen_fixed_num() -> Result<(), Box<dyn std::error::Error>> {
    let tmp_dir = TempDir::new("example")?;
    base_test(&tmp_dir, |cmd| {
        cmd.arg("--generate-exact")
            .arg("3")
            .arg("--fix-rs-include-name");
    })?;
    assert_contentful(&tmp_dir, "gen0.cc");
    assert_exists(&tmp_dir, "gen1.cc");
    assert_exists(&tmp_dir, "gen2.cc");
    assert_contentful(&tmp_dir, "gen0.include.rs");
    assert_exists(&tmp_dir, "gen1.include.rs");
    assert_exists(&tmp_dir, "gen2.include.rs");
    Ok(())
}

#[test]
fn test_gen_preprocess() -> Result<(), Box<dyn std::error::Error>> {
    let tmp_dir = TempDir::new("example")?;
    let prepro_path = tmp_dir.path().join("preprocessed.h");
    base_test(&tmp_dir, |cmd| {
        cmd.env("AUTOCXX_PREPROCESS", prepro_path.to_str().unwrap());
    })?;
    assert_contentful(&tmp_dir, "preprocessed.h");
    // Check that a random thing from one of the headers in
    // `ALL_KNOWN_SYSTEM_HEADERS` is included.
    assert!(std::fs::read_to_string(prepro_path)?.contains("integer_sequence"));
    Ok(())
}

fn write_to_file(dir: &Path, filename: &str, content: &[u8]) {
    let path = dir.join(filename);
    let mut f = File::create(&path).expect("Unable to create file");
    f.write_all(content).expect("Unable to write file");
}

fn assert_contentful(outdir: &TempDir, fname: &str) {
    let p = outdir.path().join(fname);
    if !p.exists() {
        panic!("File {} didn't exist", p.to_string_lossy());
    }
    assert!(p.metadata().unwrap().len() > super::BLANK.len().try_into().unwrap());
}

fn assert_exists(outdir: &TempDir, fname: &str) {
    let p = outdir.path().join(fname);
    if !p.exists() {
        panic!("File {} didn't exist", p.to_string_lossy());
    }
}
<|endoftext|>


<commit_before><commit_msg>NodeTSpan: make the dx/dy fields Option<Length><commit_after><|endoftext|>


<commit_before>//! A simple adaptive threadpool that returns a oneshot future.

use std::{collections::VecDeque, thread, time::Duration};

use parking_lot::{Condvar, Mutex};

use crate::{
    debug_delay, warn, AtomicBool, AtomicUsize, Lazy, OneShot, Relaxed, SeqCst,
};

const MAX_THREADS: usize = 128;
const MIN_THREADS: usize = 2;

static STANDBY_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static TOTAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);

type Work = Box<dyn FnOnce() + Send + 'static>;

struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        while queue.is_empty() {
            self.cv.wait_for(&mut queue, duration);
        }

        queue.pop_front()
    }

    fn try_recv(&self) -> Option<Work> {
        let mut queue = self.mu.lock();
        queue.pop_front()
    }

    fn send(&self, work: Work) {
        let mut queue = self.mu.lock();
        queue.push_back(work);
        self.cv.notify_one();
    }
}

static QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(init_queue);

fn init_queue() -> Queue {
    maybe_spawn_new_thread();
    Queue { cv: Condvar::new(), mu: Mutex::new(VecDeque::new()) }
}

fn perform_work() {
    let wait_limit = Duration::from_secs(1);

    while STANDBY_THREAD_COUNT.load(SeqCst) < MIN_THREADS {
        debug_delay();
        STANDBY_THREAD_COUNT.fetch_add(1, SeqCst);

        debug_delay();
        let task_res = QUEUE.recv_timeout(wait_limit);

        debug_delay();
        if STANDBY_THREAD_COUNT.fetch_sub(1, SeqCst) <= MIN_THREADS {
            maybe_spawn_new_thread();
        }

        if let Some(task) = task_res {
            (task)();
        }

        debug_delay();
        while let Some(task) = QUEUE.try_recv() {
            (task)();
            debug_delay();
        }

        debug_delay();
    }
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_spawn_new_thread() {
    debug_delay();
    let total_workers = TOTAL_THREAD_COUNT.load(SeqCst);
    debug_delay();
    let standby_workers = STANDBY_THREAD_COUNT.load(SeqCst);
    if standby_workers >= MIN_THREADS || total_workers >= MAX_THREADS {
        return;
    }

    let spawn_res =
        thread::Builder::new().name("sled-io".to_string()).spawn(|| {
            debug_delay();
            TOTAL_THREAD_COUNT.fetch_add(1, SeqCst);
            perform_work();
            TOTAL_THREAD_COUNT.fetch_sub(1, SeqCst);
        });

    if let Err(e) = spawn_res {
        once!({
            warn!(
                "Failed to dynamically increase the threadpool size: {:?}. \
                 Currently have {} running IO threads",
                e, total_workers
            )
        });
    }
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> OneShot<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    QUEUE.send(Box::new(task));

    maybe_spawn_new_thread();

    promise
}
<commit_msg>Fix queue recv_timeout<commit_after>//! A simple adaptive threadpool that returns a oneshot future.

use std::{
    collections::VecDeque,
    thread,
    time::{Duration, Instant},
};

use parking_lot::{Condvar, Mutex};

use crate::{
    debug_delay, warn, AtomicBool, AtomicUsize, Lazy, OneShot, Relaxed, SeqCst,
};

const MAX_THREADS: usize = 128;
const MIN_THREADS: usize = 2;

static STANDBY_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static TOTAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);

type Work = Box<dyn FnOnce() + Send + 'static>;

struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        let cutoff = Instant::now() + duration;

        while queue.is_empty() {
            self.cv.wait_until(&mut queue, cutoff);
        }

        queue.pop_front()
    }

    fn try_recv(&self) -> Option<Work> {
        let mut queue = self.mu.lock();
        queue.pop_front()
    }

    fn send(&self, work: Work) {
        let mut queue = self.mu.lock();
        queue.push_back(work);
        self.cv.notify_one();
    }
}

static QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(init_queue);

fn init_queue() -> Queue {
    maybe_spawn_new_thread();
    Queue { cv: Condvar::new(), mu: Mutex::new(VecDeque::new()) }
}

fn perform_work() {
    let wait_limit = Duration::from_secs(1);

    while STANDBY_THREAD_COUNT.load(SeqCst) < MIN_THREADS {
        debug_delay();
        STANDBY_THREAD_COUNT.fetch_add(1, SeqCst);

        debug_delay();
        let task_res = QUEUE.recv_timeout(wait_limit);

        debug_delay();
        if STANDBY_THREAD_COUNT.fetch_sub(1, SeqCst) <= MIN_THREADS {
            maybe_spawn_new_thread();
        }

        if let Some(task) = task_res {
            (task)();
        }

        debug_delay();
        while let Some(task) = QUEUE.try_recv() {
            (task)();
            debug_delay();
        }

        debug_delay();
    }
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_spawn_new_thread() {
    debug_delay();
    let total_workers = TOTAL_THREAD_COUNT.load(SeqCst);
    debug_delay();
    let standby_workers = STANDBY_THREAD_COUNT.load(SeqCst);
    if standby_workers >= MIN_THREADS || total_workers >= MAX_THREADS {
        return;
    }

    let spawn_res =
        thread::Builder::new().name("sled-io".to_string()).spawn(|| {
            debug_delay();
            TOTAL_THREAD_COUNT.fetch_add(1, SeqCst);
            perform_work();
            TOTAL_THREAD_COUNT.fetch_sub(1, SeqCst);
        });

    if let Err(e) = spawn_res {
        once!({
            warn!(
                "Failed to dynamically increase the threadpool size: {:?}. \
                 Currently have {} running IO threads",
                e, total_workers
            )
        });
    }
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> OneShot<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    QUEUE.send(Box::new(task));

    maybe_spawn_new_thread();

    promise
}
<|endoftext|>


<commit_before>use crate::tls::*;
use crate::tls_alert::TlsAlertSeverity;

#[derive(Debug, PartialEq, Eq)]
/// Error types for the state machine
pub enum StateChangeError {
    InvalidTransition,
    ParseError,
}

/// TLS machine possible states
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum TlsState {
    None,
    ClientHello,
    AskResumeSession,
    ResumeSession,
    ServerHello,
    Certificate,
    CertificateSt,
    ServerKeyExchange,
    ServerHelloDone,
    ClientKeyExchange,
    ClientChangeCipherSpec,

    CRCertRequest,
    CRHelloDone,
    CRCert,
    CRClientKeyExchange,
    CRCertVerify,

    NoCertSKE,
    NoCertHelloDone,
    NoCertCKE,

    PskHelloDone,
    PskCKE,

    SessionEncrypted,

    Alert,

    Finished,

    Invalid,
}

#[rustfmt::skip]
fn tls_state_transition_handshake(state: TlsState, msg: &TlsMessageHandshake, to_server:bool) -> Result<TlsState,StateChangeError> {
    match (state,msg,to_server) {
        (TlsState::None,             &TlsMessageHandshake::ClientHello(ref msg), true) => {
            match msg.session_id {
                Some(_) => Ok(TlsState::AskResumeSession),
                _       => Ok(TlsState::ClientHello)
            }
        },
        // Server certificate
        (TlsState::ClientHello,      &TlsMessageHandshake::ServerHello(_), false)       => Ok(TlsState::ServerHello),
        (TlsState::ServerHello,      &TlsMessageHandshake::Certificate(_), false)       => Ok(TlsState::Certificate),
        // Server certificate, no client certificate requested
        (TlsState::Certificate,      &TlsMessageHandshake::ServerKeyExchange(_), false) => Ok(TlsState::ServerKeyExchange),
        (TlsState::Certificate,      &TlsMessageHandshake::CertificateStatus(_), false) => Ok(TlsState::CertificateSt),
        (TlsState::CertificateSt,    &TlsMessageHandshake::ServerKeyExchange(_), false) => Ok(TlsState::ServerKeyExchange),
        (TlsState::ServerKeyExchange,&TlsMessageHandshake::ServerDone(_), false)        => Ok(TlsState::ServerHelloDone),
        (TlsState::ServerHelloDone  ,&TlsMessageHandshake::ClientKeyExchange(_), true)  => Ok(TlsState::ClientKeyExchange),
        // Server certificate, client certificate requested
        (TlsState::Certificate,      &TlsMessageHandshake::CertificateRequest(_), false)=> Ok(TlsState::CRCertRequest),
        (TlsState::ServerKeyExchange,&TlsMessageHandshake::CertificateRequest(_), false)=> Ok(TlsState::CRCertRequest),
        (TlsState::CRCertRequest,    &TlsMessageHandshake::ServerDone(_), false)        => Ok(TlsState::CRHelloDone),
        (TlsState::CRHelloDone,      &TlsMessageHandshake::Certificate(_), true)        => Ok(TlsState::CRCert),
        (TlsState::CRCert,           &TlsMessageHandshake::ClientKeyExchange(_), true)  => Ok(TlsState::CRClientKeyExchange),
        (TlsState::CRClientKeyExchange, &TlsMessageHandshake::CertificateVerify(_), _)  => Ok(TlsState::CRCertVerify),
        // Server has no certificate (but accepts anonymous)
        (TlsState::ServerHello,      &TlsMessageHandshake::ServerKeyExchange(_), false) => Ok(TlsState::NoCertSKE),
        (TlsState::NoCertSKE,        &TlsMessageHandshake::ServerDone(_), false)        => Ok(TlsState::NoCertHelloDone),
        (TlsState::NoCertHelloDone,  &TlsMessageHandshake::ClientKeyExchange(_), true)  => Ok(TlsState::NoCertCKE),
        // PSK
        (TlsState::Certificate,      &TlsMessageHandshake::ServerDone(_), false)        => Ok(TlsState::PskHelloDone),
        (TlsState::PskHelloDone,     &TlsMessageHandshake::ClientKeyExchange(_), true)  => Ok(TlsState::PskCKE),
        // Resuming session
        (TlsState::AskResumeSession, &TlsMessageHandshake::ServerHello(_), false)       => Ok(TlsState::ResumeSession),
        // Resume session failed
        (TlsState::ResumeSession,    &TlsMessageHandshake::Certificate(_), false)       => Ok(TlsState::Certificate),
        // TLS 1.3 Draft 18 1-RTT
        // Re-use the ClientChangeCipherSpec state to indicate the next message will be encrypted
        (TlsState::ClientHello,      &TlsMessageHandshake::ServerHelloV13Draft18(_), false)    => Ok(TlsState::ClientChangeCipherSpec),
        // Hello requests must be accepted at any time (except start), but ignored [RFC5246] 7.4.1.1
        (TlsState::None,             &TlsMessageHandshake::HelloRequest, _)             => Err(StateChangeError::InvalidTransition),
        (s,                          &TlsMessageHandshake::HelloRequest, _)             => Ok(s),
        // All other transitions are considered invalid
        _ => Err(StateChangeError::InvalidTransition),
    }
}

/// Update the TLS state machine, doing one transition
///
/// Given the previous state and the parsed message, return the new state or a state machine error.
///
/// This state machine only implements the TLS handshake.
///
/// Some transitions only check the new message type, while some others must match the content
/// (for example, to check if the client asked to resume a session).
///
/// If the previous state is `Invalid`, the state machine will not return an error, but keep the
/// same `Invalid` state. This is used to raise error only once if the state machine keeps being
/// updated by new messages.
#[rustfmt::skip]
pub fn tls_state_transition(state: TlsState, msg: &TlsMessage, to_server:bool) -> Result<TlsState,StateChangeError> {
    match (state,msg,to_server) {
        (TlsState::Invalid,_,_) => Ok(TlsState::Invalid),
        (TlsState::Finished,_,_) => Ok(TlsState::Invalid),
        (_,&TlsMessage::Handshake(ref m),_) => tls_state_transition_handshake(state,m,to_server),
        // Server certificate
        (TlsState::ClientKeyExchange,     &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec),
        (TlsState::ClientChangeCipherSpec,&TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::SessionEncrypted),
        // Server certificate, client certificate requested
        (TlsState::CRClientKeyExchange,   &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec),
        (TlsState::CRCertVerify,          &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec),
        // No server certificate
        (TlsState::NoCertCKE,             &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec),
        // PSK
        (TlsState::PskCKE,                &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec),
        // Resume session
        (TlsState::ResumeSession,         &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec),
        // 0-rtt
        (TlsState::AskResumeSession,      &TlsMessage::ChangeCipherSpec, true) => Ok(TlsState::AskResumeSession),
        // non-fatal alerts
        (s,                               &TlsMessage::Alert(ref a), _) => {
            if a.severity == TlsAlertSeverity::Warning { Ok(s) } else { Ok(TlsState::Finished) }
        },
        (_,_,_) => Err(StateChangeError::InvalidTransition),
    }
}
<commit_msg>State machine: accept NewSessionTicket after Client CCS<commit_after>use crate::tls::*;
use crate::tls_alert::TlsAlertSeverity;

#[derive(Debug, PartialEq, Eq)]
/// Error types for the state machine
pub enum StateChangeError {
    InvalidTransition,
    ParseError,
}

/// TLS machine possible states
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum TlsState {
    None,
    ClientHello,
    AskResumeSession,
    ResumeSession,
    ServerHello,
    Certificate,
    CertificateSt,
    ServerKeyExchange,
    ServerHelloDone,
    ClientKeyExchange,
    ClientChangeCipherSpec,

    CRCertRequest,
    CRHelloDone,
    CRCert,
    CRClientKeyExchange,
    CRCertVerify,

    NoCertSKE,
    NoCertHelloDone,
    NoCertCKE,

    PskHelloDone,
    PskCKE,

    SessionEncrypted,

    Alert,

    Finished,

    Invalid,
}

#[rustfmt::skip]
fn tls_state_transition_handshake(state: TlsState, msg: &TlsMessageHandshake, to_server:bool) -> Result<TlsState,StateChangeError> {
    match (state,msg,to_server) {
        (TlsState::None,             &TlsMessageHandshake::ClientHello(ref msg), true) => {
            match msg.session_id {
                Some(_) => Ok(TlsState::AskResumeSession),
                _       => Ok(TlsState::ClientHello)
            }
        },
        // Server certificate
        (TlsState::ClientHello,      &TlsMessageHandshake::ServerHello(_), false)       => Ok(TlsState::ServerHello),
        (TlsState::ServerHello,      &TlsMessageHandshake::Certificate(_), false)       => Ok(TlsState::Certificate),
        // Server certificate, no client certificate requested
        (TlsState::Certificate,      &TlsMessageHandshake::ServerKeyExchange(_), false) => Ok(TlsState::ServerKeyExchange),
        (TlsState::Certificate,      &TlsMessageHandshake::CertificateStatus(_), false) => Ok(TlsState::CertificateSt),
        (TlsState::CertificateSt,    &TlsMessageHandshake::ServerKeyExchange(_), false) => Ok(TlsState::ServerKeyExchange),
        (TlsState::ServerKeyExchange,&TlsMessageHandshake::ServerDone(_), false)        => Ok(TlsState::ServerHelloDone),
        (TlsState::ServerHelloDone  ,&TlsMessageHandshake::ClientKeyExchange(_), true)  => Ok(TlsState::ClientKeyExchange),
        // Server certificate, client certificate requested
        (TlsState::Certificate,      &TlsMessageHandshake::CertificateRequest(_), false)=> Ok(TlsState::CRCertRequest),
        (TlsState::ServerKeyExchange,&TlsMessageHandshake::CertificateRequest(_), false)=> Ok(TlsState::CRCertRequest),
        (TlsState::CRCertRequest,    &TlsMessageHandshake::ServerDone(_), false)        => Ok(TlsState::CRHelloDone),
        (TlsState::CRHelloDone,      &TlsMessageHandshake::Certificate(_), true)        => Ok(TlsState::CRCert),
        (TlsState::CRCert,           &TlsMessageHandshake::ClientKeyExchange(_), true)  => Ok(TlsState::CRClientKeyExchange),
        (TlsState::CRClientKeyExchange, &TlsMessageHandshake::CertificateVerify(_), _)  => Ok(TlsState::CRCertVerify),
        // Server has no certificate (but accepts anonymous)
        (TlsState::ServerHello,      &TlsMessageHandshake::ServerKeyExchange(_), false) => Ok(TlsState::NoCertSKE),
        (TlsState::NoCertSKE,        &TlsMessageHandshake::ServerDone(_), false)        => Ok(TlsState::NoCertHelloDone),
        (TlsState::NoCertHelloDone,  &TlsMessageHandshake::ClientKeyExchange(_), true)  => Ok(TlsState::NoCertCKE),
        // PSK
        (TlsState::Certificate,      &TlsMessageHandshake::ServerDone(_), false)        => Ok(TlsState::PskHelloDone),
        (TlsState::PskHelloDone,     &TlsMessageHandshake::ClientKeyExchange(_), true)  => Ok(TlsState::PskCKE),
        // Resuming session
        (TlsState::AskResumeSession, &TlsMessageHandshake::ServerHello(_), false)       => Ok(TlsState::ResumeSession),
        // Resume session failed
        (TlsState::ResumeSession,    &TlsMessageHandshake::Certificate(_), false)       => Ok(TlsState::Certificate),
        // TLS 1.3 Draft 18 1-RTT
        // Re-use the ClientChangeCipherSpec state to indicate the next message will be encrypted
        (TlsState::ClientHello,      &TlsMessageHandshake::ServerHelloV13Draft18(_), false)    => Ok(TlsState::ClientChangeCipherSpec),
        // Hello requests must be accepted at any time (except start), but ignored [RFC5246] 7.4.1.1
        (TlsState::None,             &TlsMessageHandshake::HelloRequest, _)             => Err(StateChangeError::InvalidTransition),
        (s,                          &TlsMessageHandshake::HelloRequest, _)             => Ok(s),
        // NewSessionTicket message (after CCS)
        (TlsState::ClientChangeCipherSpec,    &TlsMessageHandshake::NewSessionTicket(_), false)  => Ok(TlsState::ClientChangeCipherSpec),
        // All other transitions are considered invalid
        _ => Err(StateChangeError::InvalidTransition),
    }
}

/// Update the TLS state machine, doing one transition
///
/// Given the previous state and the parsed message, return the new state or a state machine error.
///
/// This state machine only implements the TLS handshake.
///
/// Some transitions only check the new message type, while some others must match the content
/// (for example, to check if the client asked to resume a session).
///
/// If the previous state is `Invalid`, the state machine will not return an error, but keep the
/// same `Invalid` state. This is used to raise error only once if the state machine keeps being
/// updated by new messages.
#[rustfmt::skip]
pub fn tls_state_transition(state: TlsState, msg: &TlsMessage, to_server:bool) -> Result<TlsState,StateChangeError> {
    match (state,msg,to_server) {
        (TlsState::Invalid,_,_) => Ok(TlsState::Invalid),
        (TlsState::SessionEncrypted,_, _) => Ok(TlsState::SessionEncrypted),
        (TlsState::Finished,_,_) => Ok(TlsState::Invalid),
        (_,&TlsMessage::Handshake(ref m),_) => tls_state_transition_handshake(state,m,to_server),
        // Server certificate
        (TlsState::ClientKeyExchange,     &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec),
        (TlsState::ClientChangeCipherSpec,&TlsMessage::ChangeCipherSpec, false) => Ok(TlsState::SessionEncrypted),
        // Server certificate, client certificate requested
        (TlsState::CRClientKeyExchange,   &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec),
        (TlsState::CRCertVerify,          &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec),
        // No server certificate
        (TlsState::NoCertCKE,             &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec),
        // PSK
        (TlsState::PskCKE,                &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec),
        // Resume session
        (TlsState::ResumeSession,         &TlsMessage::ChangeCipherSpec, _) => Ok(TlsState::ClientChangeCipherSpec),
        // 0-rtt
        (TlsState::AskResumeSession,      &TlsMessage::ChangeCipherSpec, true) => Ok(TlsState::AskResumeSession),
        // non-fatal alerts
        (s,                               &TlsMessage::Alert(ref a), _) => {
            if a.severity == TlsAlertSeverity::Warning { Ok(s) } else { Ok(TlsState::Finished) }
        },
        (_,_,_) => Err(StateChangeError::InvalidTransition),
    }
}
<|endoftext|>


<commit_before>//! Traits for the game

pub mod view;
mod map;

pub use self::view::View;
pub use self::map::*;

/// A trait for positioned objects
pub trait Positioned {
  /// Get the x coordinate
  fn get_x(&self) -> i64;
  /// Get the y coordinate
  fn get_y(&self) -> i64;
  /// Set the x coordinate
  fn set_x(&mut self, new_x: i64);
  /// Set the y coordinate
  fn set_y(&mut self, new_y: i64);
}

// TODO: Isn't a trait should be moved.
/// The direction of a given object
#[derive(Clone, Copy)]
pub enum Dir {
  Left,
  Right,
  Up,
  Down,
}

// TODO: Implement two directions at once.
// TODO: Make drawable trait

// A movable object
pub trait Movable: Positioned {
  /// Get the direction
  fn get_dir(&self) -> Dir;
  /// Set the direction
  fn set_dir(&mut self, new_dir: Dir);
  /// Move the object
  fn move_obj(&mut self, mov_x: i64, mov_y: i64) {
    let x = self.get_x();
    let y = self.get_y();
    self.set_x(x + mov_x);
    self.set_y(y + mov_y);
  }
  /// Take a step in the current direction
  fn take_step(&mut self) {
    let dir = self.get_dir();
    self.move_obj(

      match dir {
        Dir::Left => 1,
        Dir::Right => -1,
        Dir::Up => 0,
        Dir::Down => 0,
      },

      match dir {
        Dir::Left => 0,
        Dir::Right => 0,
        Dir::Up => 1,
        Dir::Down => -1,
      }

    );
  }
}
<commit_msg>Make minor refactoring<commit_after>//! Traits for the game

pub mod view;
mod map;

pub use self::view::View;
pub use self::map::*;

/// A trait for positioned objects
pub trait Positioned {
  /// Get the x coordinate
  fn get_x(&self) -> i64;
  /// Get the y coordinate
  fn get_y(&self) -> i64;
  /// Set the x coordinate
  fn set_x(&mut self, new_x: i64);
  /// Set the y coordinate
  fn set_y(&mut self, new_y: i64);
}

// TODO: Isn't a trait should be moved.
/// The direction of a given object
#[derive(Clone, Copy)]
pub enum Dir {
  Left,
  Right,
  Up,
  Down,
}

// TODO: Implement two directions at once.
// TODO: Make drawable trait

// A movable object
pub trait Movable: Positioned {
  /// Get the direction
  fn get_dir(&self) -> Dir;
  /// Set the direction
  fn set_dir(&mut self, new_dir: Dir);
  /// Move the object
  fn move_obj(&mut self, mov_x: i64, mov_y: i64) {
    let x = self.get_x();
    let y = self.get_y();
    self.set_x(x + mov_x);
    self.set_y(y + mov_y);
  }
  /// Take a step in the current direction
  fn take_step(&mut self) {
    let dir = self.get_dir();
    self.move_obj(

      match dir {
        Dir::Left => 1,
        Dir::Right => -1,
        _ => 0,
      },

      match dir {
        Dir::Up => 1,
        Dir::Down => -1,
        _ => 0,
      }

    );
  }
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use super::super::direction::Direction::*;
use super::Wall;

impl Wall {
    /// Print a labyrinth to stdout using UNICODE BOX characters.
    pub fn print(&self) {
        let mut stdout = io::stdout();
        let mut writer = |s: &str| { stdout.write_all(s.as_bytes()).unwrap() };
        self.draw(&mut writer);
    }
    /// Draw a labyrinth as a String using UNICODE BOX characters.
    pub fn to_string(&self) -> String {
        let mut out = String::new();
        self.draw(&mut |s: &str| { out.push_str(s) });
        out
    }
    /// Draw a labyrinth using UNICODE BOX characters to a `writer`.
    pub fn draw(&self, writer: &mut FnMut(&str)) {
        for y in 0..self.rows {
            for x in 0..self.cols {
                if x == 0 || self.is_open(x - 1, y, Up) {
                    if y == 0 || self.is_open(x, y - 1, Left) {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "  " } else { "╻ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "╺━" } else { "┏━" });
                        }
                    } else {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "╹ " } else { "┃ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "┗━" } else { "┣━" });
                        }
                    }
                } else {
                    if y == 0 || self.is_open(x, y - 1, Left) {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "╸ " } else { "┓ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "━━" } else { "┳━" });
                        }
                    } else {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "┛ " } else { "┫ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "┻━" } else { "╋━" });
                        }
                    }
                }
            }
            let x = self.cols;
            if self.is_open(x - 1, y, Up) {
                if y == 0 || self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Left) { " " } else { "╻" });
                } else {
                    writer(if self.is_open(x, y, Left) { "╹" } else { "┃" });
                }
            } else {
                if y == 0 || self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Left) { "╸" } else { "┓" });
                } else {
                    writer(if self.is_open(x, y, Left) { "┛" } else { "┫" });
                }
            }
            writer("\n");
        }
        let y = self.rows;
        for x in 0..self.cols {
            if x == 0 || self.is_open(x - 1, y, Up) {
                if self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Up) { "  " } else { "╺━" });
                } else {
                    writer(if self.is_open(x, y, Up) { "╹ " } else { "┗━" });
                }
            } else {
                if y == 0 || self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Up) { "╸ " } else { "━━" });
                } else {
                    writer(if self.is_open(x, y, Up) { "┛ " } else { "┻━" });
                }
            }
        }
        let x = self.cols;
        if self.is_open(x - 1, y, Up) {
            writer(if self.is_open(x, y - 1, Left) { " " } else { "╹" });
        } else {
            writer(if self.is_open(x, y - 1, Left) { "╸" } else { "┛" });
        }
        writer("\n");
    }
}

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

    #[test]
    fn should_draw_a_labyrinth() {
        let mut labyrinth = Wall::new(2, 2);
        assert_eq!(
"┏━┳━┓
┣━╋━┫
┗━┻━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 0, Right);
        assert_eq!(
"┏━━━┓
┣━┳━┫
┗━┻━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 0, Down);
        assert_eq!(
"┏━━━┓
┣━┓ ┃
┗━┻━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 1, Left);
        assert_eq!(
"┏━━━┓
┣━╸ ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 1, Up);
        assert_eq!(
"┏━━━┓
┃   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 0, Left);
        assert_eq!(
"╺━━━┓
╻   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 0, Up);
        assert_eq!(
"  ╺━┓
╻   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 0, Up);
        assert_eq!(
"    ╻
╻   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 0, Right);
        assert_eq!(
"
╻   ╻
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 1, Left);
        assert_eq!(
"
    ╻
╺━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 1, Down);
        assert_eq!(
"
    ╻
  ╺━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 1, Down);
        assert_eq!(
"
    ╻
    ╹
",      &labyrinth.to_string());
        labyrinth.open(1, 1, Right);
        assert_eq!(
"

",      &labyrinth.to_string());

    }
}
<commit_msg>use dyn in trait object argument type<commit_after>use std::io::{self, Write};
use super::super::direction::Direction::*;
use super::Wall;

impl Wall {
    /// Print a labyrinth to stdout using UNICODE BOX characters.
    pub fn print(&self) {
        let mut stdout = io::stdout();
        let mut writer = |s: &str| { stdout.write_all(s.as_bytes()).unwrap() };
        self.draw(&mut writer);
    }
    /// Draw a labyrinth as a String using UNICODE BOX characters.
    pub fn to_string(&self) -> String {
        let mut out = String::new();
        self.draw(&mut |s: &str| { out.push_str(s) });
        out
    }
    /// Draw a labyrinth using UNICODE BOX characters to a `writer`.
    pub fn draw(&self, writer: &mut dyn FnMut(&str)) {
        for y in 0..self.rows {
            for x in 0..self.cols {
                if x == 0 || self.is_open(x - 1, y, Up) {
                    if y == 0 || self.is_open(x, y - 1, Left) {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "  " } else { "╻ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "╺━" } else { "┏━" });
                        }
                    } else {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "╹ " } else { "┃ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "┗━" } else { "┣━" });
                        }
                    }
                } else {
                    if y == 0 || self.is_open(x, y - 1, Left) {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "╸ " } else { "┓ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "━━" } else { "┳━" });
                        }
                    } else {
                        if self.is_open(x, y, Up) {
                            writer(if self.is_open(x, y, Left) { "┛ " } else { "┫ " });
                        } else {
                            writer(if self.is_open(x, y, Left) { "┻━" } else { "╋━" });
                        }
                    }
                }
            }
            let x = self.cols;
            if self.is_open(x - 1, y, Up) {
                if y == 0 || self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Left) { " " } else { "╻" });
                } else {
                    writer(if self.is_open(x, y, Left) { "╹" } else { "┃" });
                }
            } else {
                if y == 0 || self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Left) { "╸" } else { "┓" });
                } else {
                    writer(if self.is_open(x, y, Left) { "┛" } else { "┫" });
                }
            }
            writer("\n");
        }
        let y = self.rows;
        for x in 0..self.cols {
            if x == 0 || self.is_open(x - 1, y, Up) {
                if self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Up) { "  " } else { "╺━" });
                } else {
                    writer(if self.is_open(x, y, Up) { "╹ " } else { "┗━" });
                }
            } else {
                if y == 0 || self.is_open(x, y - 1, Left) {
                    writer(if self.is_open(x, y, Up) { "╸ " } else { "━━" });
                } else {
                    writer(if self.is_open(x, y, Up) { "┛ " } else { "┻━" });
                }
            }
        }
        let x = self.cols;
        if self.is_open(x - 1, y, Up) {
            writer(if self.is_open(x, y - 1, Left) { " " } else { "╹" });
        } else {
            writer(if self.is_open(x, y - 1, Left) { "╸" } else { "┛" });
        }
        writer("\n");
    }
}

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

    #[test]
    fn should_draw_a_labyrinth() {
        let mut labyrinth = Wall::new(2, 2);
        assert_eq!(
"┏━┳━┓
┣━╋━┫
┗━┻━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 0, Right);
        assert_eq!(
"┏━━━┓
┣━┳━┫
┗━┻━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 0, Down);
        assert_eq!(
"┏━━━┓
┣━┓ ┃
┗━┻━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 1, Left);
        assert_eq!(
"┏━━━┓
┣━╸ ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 1, Up);
        assert_eq!(
"┏━━━┓
┃   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 0, Left);
        assert_eq!(
"╺━━━┓
╻   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 0, Up);
        assert_eq!(
"  ╺━┓
╻   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 0, Up);
        assert_eq!(
"    ╻
╻   ┃
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 0, Right);
        assert_eq!(
"
╻   ╻
┗━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 1, Left);
        assert_eq!(
"
    ╻
╺━━━┛
",      &labyrinth.to_string());
        labyrinth.open(0, 1, Down);
        assert_eq!(
"
    ╻
  ╺━┛
",      &labyrinth.to_string());
        labyrinth.open(1, 1, Down);
        assert_eq!(
"
    ╻
    ╹
",      &labyrinth.to_string());
        labyrinth.open(1, 1, Right);
        assert_eq!(
"

",      &labyrinth.to_string());

    }
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::rc::{Rc};
use num::{Float};
use image;
use glium::{self, texture, framebuffer, Surface};
use super::{CanvasMagnify};
use super::mesh;
use ::{V2, Rect};
use ::rgb::{to_srgb};

pub struct Renderer {
    /// Canvas size.
    size: V2<u32>,
    /// Rendering device resolution.
    resolution: V2<u32>,
    /// Shader for drawing atlas images.
    sprite_shader: Rc<glium::Program>,
    /// Shader for blitting the canvas texture to screen.
    blit_shader: glium::Program,
    /// Atlas texture, contains all the sprites. Calx is a low-rent operation
    /// so we only have one.
    atlas: Rc<texture::Texture2d>,
    /// Render target texture.
    buffer: texture::Texture2d,
    depth: framebuffer::DepthRenderBuffer,
    magnify: CanvasMagnify,
}

impl Renderer {
    pub fn new<'a, T>(
        size: V2<u32>, display: &glium::Display,
        texture_image: T, magnify: CanvasMagnify) -> Renderer
        where T: texture::Texture2dDataSource<'a> {

        let sprite_shader = Rc::new(glium::Program::from_source(display,
            include_str!("sprite.vert"),
            include_str!("sprite.frag"),
            None).unwrap());
        let blit_shader = glium::Program::from_source(display,
            include_str!("blit.vert"),
            include_str!("blit.frag"),
            None).unwrap();
        let atlas = Rc::new(texture::Texture2d::new(display, texture_image).unwrap());

        let buffer = texture::Texture2d::empty(
            display, size.0, size.1).unwrap();
        let depth = framebuffer::DepthRenderBuffer::new(
            display, texture::DepthFormat::F32, size.0, size.1);

        Renderer {
            size: size,
            resolution: size,
            sprite_shader: sprite_shader,
            blit_shader: blit_shader,
            atlas: atlas,
            buffer: buffer,
            depth: depth,
            magnify: magnify,
        }
    }

    /// Blit the buffer texture to target.
    fn blit_buffer<S>(&self, display: &glium::Display, target: &mut S)
        where S: glium::Surface {
        // TODO: Pixel-perfect scaling to target dimensions.
        //
        let Rect(V2(sx, sy), V2(sw, sh)) = match self.magnify {
            CanvasMagnify::PixelPerfect => pixel_perfect(self.size, self.resolution),
            _ => preserve_aspect(self.size, self.resolution),
        };

        let vertices = {
            #[derive(Copy, Clone)]
            struct BlitVertex { pos: [f32; 2], tex_coord: [f32; 2] }
            implement_vertex!(BlitVertex, pos, tex_coord);

            glium::VertexBuffer::new(display,
            &[
                BlitVertex { pos: [sx,    sy   ], tex_coord: [0.0, 0.0] },
                BlitVertex { pos: [sx+sw, sy   ], tex_coord: [1.0, 0.0] },
                BlitVertex { pos: [sx+sw, sy+sh], tex_coord: [1.0, 1.0] },
                BlitVertex { pos: [sx,    sy+sh], tex_coord: [0.0, 1.0] },
            ]).unwrap()
        };

        let indices = glium::IndexBuffer::new(display,
            glium::index::PrimitiveType::TrianglesList, &[0u16, 1, 2, 0, 2, 3]).unwrap();

        let mut params: glium::DrawParameters = Default::default();
        // Set an explicit viewport to apply the custom resolution that fixes
        // pixel perfect rounding errors.
        params.viewport = Some(glium::Rect{
            left: 0, bottom: 0,
            width: self.resolution.0,
            height: self.resolution.1 });

        let mag_filter = match self.magnify {
            CanvasMagnify::Smooth => glium::uniforms::MagnifySamplerFilter::Linear,
            _ => glium::uniforms::MagnifySamplerFilter::Nearest
        };

        let uniforms = glium::uniforms::UniformsStorage::new("tex",
            glium::uniforms::Sampler(&self.buffer, glium::uniforms::SamplerBehavior {
                magnify_filter: mag_filter,
                minify_filter: glium::uniforms::MinifySamplerFilter::Linear,
                .. Default::default() }));

        target.draw(&vertices, &indices, &self.blit_shader, &uniforms, &params).unwrap();
    }

    /// Call at the start of drawing
    pub fn init(&mut self, display: &glium::Display) {
        let mut target = framebuffer::SimpleFrameBuffer::with_depth_buffer(
            display, &self.buffer, &self.depth);
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        target.clear_depth(1.0);
    }

    /// Draw a geometry buffer.
    pub fn draw(&mut self, display: &glium::Display,
                vertices: Vec<mesh::Vertex>, indices: Vec<u16>) {
        // Render the graphics to a texture to keep the pixels pure and
        // untainted.
        let mut sprite_target = framebuffer::SimpleFrameBuffer::with_depth_buffer(
            display, &self.buffer, &self.depth);
        let mut mesh_buffer = mesh::Buffer::new(self.sprite_shader.clone(), self.atlas.clone());
        let mut triangles = Vec::new();
        for i in 0..(indices.len() / 3) {
            triangles.push([indices[i * 3], indices[i * 3 + 1], indices[i * 3 + 2]]);
        }
        mesh_buffer.push(vertices, triangles);
        mesh_buffer.flush(display, &mut sprite_target);
    }

    /// Show the drawn geometry on screen.
    pub fn show<S>(&mut self, display: &glium::Display, target: &mut S)
        where S: glium::Surface
    {
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        target.clear_depth(1.0);
        let (w, h) = display.get_framebuffer_dimensions();
        // Clip viewport dimensions to even to prevent rounding errors in
        // pixel perfect scaling.
        self.resolution = V2(w & !1, h & !1);
        // Render the texture to screen.
        self.blit_buffer(display, target);
    }

    /// Map screen position (eg. of a mouse cursor) to canvas position.
    pub fn screen_to_canvas(&self, V2(sx, sy): V2<i32>) -> V2<i32> {
        let Rect(V2(rx, ry), V2(rw, rh)) = pixel_perfect(self.size, self.resolution);
        // Transform to device coordinates.
        let sx = sx as f32 * 2.0 / self.resolution.0 as f32 - 1.0;
        let sy = sy as f32 * 2.0 / self.resolution.1 as f32 - 1.0;

        V2(((sx - rx) * self.size.0 as f32 / rw) as i32,
           ((sy - ry) * self.size.1 as f32 / rh) as i32)
    }

    pub fn canvas_pixels(&self) -> image::ImageBuffer<image::Rgb<u8>, Vec<u8>> {
        let mut ret = self.buffer.read::<image::DynamicImage>().to_rgb();

        // Convert to sRGB
        // XXX: Probably horribly slow, can we make OpenGL do this?
        for p in ret.pixels_mut() {
            p.data[0] = (to_srgb(p.data[0] as f32 / 255.0) * 255.0).round() as u8;
            p.data[1] = (to_srgb(p.data[1] as f32 / 255.0) * 255.0).round() as u8;
            p.data[2] = (to_srgb(p.data[2] as f32 / 255.0) * 255.0).round() as u8;
        }

        ret
    }
}

/// A pixel perfect centered and scaled rectangle of resolution dim in a
/// window of size area, mapped to OpenGL device coordinates.
#[inline(always)]
fn pixel_perfect(canvas: V2<u32>, window: V2<u32>) -> Rect<f32> {
    // Scale based on whichever of X or Y axis is the tighter fit.
    let mut scale = (window.0 as f32 / canvas.0 as f32)
        .min(window.1 as f32 / canvas.1 as f32);

    if scale > 1.0 {
        // Snap to pixel scale if more than 1 window pixel per canvas pixel.
        scale = scale.floor();
    }

    let dim = V2((scale * canvas.0 as f32) * 2.0 / window.0 as f32,
                 (scale * canvas.1 as f32) * 2.0 / window.1 as f32);
    let offset = -dim / 2.0;
    Rect(offset, dim)
}

#[inline(always)]
fn preserve_aspect(canvas: V2<u32>, window: V2<u32>) -> Rect<f32> {
    // Scale based on whichever of X or Y axis is the tighter fit.
    let scale = (window.0 as f32 / canvas.0 as f32)
        .min(window.1 as f32 / canvas.1 as f32);

    let dim = V2((scale * canvas.0 as f32) * 2.0 / window.0 as f32,
                 (scale * canvas.1 as f32) * 2.0 / window.1 as f32);
    let offset = -dim / 2.0;
    Rect(offset, dim)
}
<commit_msg>Renderer uses new mesh api<commit_after>use std::default::Default;
use std::rc::{Rc};
use num::{Float};
use image;
use glium::{self, texture, framebuffer, Surface};
use super::{CanvasMagnify};
use super::mesh;
use ::{V2, Rect};
use ::rgb::{to_srgb};

pub struct Renderer {
    /// Canvas size.
    size: V2<u32>,
    /// Rendering device resolution.
    resolution: V2<u32>,
    /// Shader for drawing atlas images.
    sprite_shader: Rc<glium::Program>,
    /// Shader for blitting the canvas texture to screen.
    blit_shader: glium::Program,
    /// Atlas texture, contains all the sprites. Calx is a low-rent operation
    /// so we only have one.
    atlas: Rc<texture::Texture2d>,
    /// Render target texture.
    buffer: texture::Texture2d,
    depth: framebuffer::DepthRenderBuffer,
    magnify: CanvasMagnify,
}

impl Renderer {
    pub fn new<'a, T>(
        size: V2<u32>, display: &glium::Display,
        texture_image: T, magnify: CanvasMagnify) -> Renderer
        where T: texture::Texture2dDataSource<'a> {

        let sprite_shader = Rc::new(glium::Program::from_source(display,
            include_str!("sprite.vert"),
            include_str!("sprite.frag"),
            None).unwrap());
        let blit_shader = glium::Program::from_source(display,
            include_str!("blit.vert"),
            include_str!("blit.frag"),
            None).unwrap();
        let atlas = Rc::new(texture::Texture2d::new(display, texture_image).unwrap());

        let buffer = texture::Texture2d::empty(
            display, size.0, size.1).unwrap();
        let depth = framebuffer::DepthRenderBuffer::new(
            display, texture::DepthFormat::F32, size.0, size.1);

        Renderer {
            size: size,
            resolution: size,
            sprite_shader: sprite_shader,
            blit_shader: blit_shader,
            atlas: atlas,
            buffer: buffer,
            depth: depth,
            magnify: magnify,
        }
    }

    /// Blit the buffer texture to target.
    fn blit_buffer<S>(&self, display: &glium::Display, target: &mut S)
        where S: glium::Surface {
        // TODO: Pixel-perfect scaling to target dimensions.
        //
        let Rect(V2(sx, sy), V2(sw, sh)) = match self.magnify {
            CanvasMagnify::PixelPerfect => pixel_perfect(self.size, self.resolution),
            _ => preserve_aspect(self.size, self.resolution),
        };

        let vertices = {
            #[derive(Copy, Clone)]
            struct BlitVertex { pos: [f32; 2], tex_coord: [f32; 2] }
            implement_vertex!(BlitVertex, pos, tex_coord);

            glium::VertexBuffer::new(display,
            &[
                BlitVertex { pos: [sx,    sy   ], tex_coord: [0.0, 0.0] },
                BlitVertex { pos: [sx+sw, sy   ], tex_coord: [1.0, 0.0] },
                BlitVertex { pos: [sx+sw, sy+sh], tex_coord: [1.0, 1.0] },
                BlitVertex { pos: [sx,    sy+sh], tex_coord: [0.0, 1.0] },
            ]).unwrap()
        };

        let indices = glium::IndexBuffer::new(display,
            glium::index::PrimitiveType::TrianglesList, &[0u16, 1, 2, 0, 2, 3]).unwrap();

        let mut params: glium::DrawParameters = Default::default();
        // Set an explicit viewport to apply the custom resolution that fixes
        // pixel perfect rounding errors.
        params.viewport = Some(glium::Rect{
            left: 0, bottom: 0,
            width: self.resolution.0,
            height: self.resolution.1 });

        let mag_filter = match self.magnify {
            CanvasMagnify::Smooth => glium::uniforms::MagnifySamplerFilter::Linear,
            _ => glium::uniforms::MagnifySamplerFilter::Nearest
        };

        let uniforms = glium::uniforms::UniformsStorage::new("tex",
            glium::uniforms::Sampler(&self.buffer, glium::uniforms::SamplerBehavior {
                magnify_filter: mag_filter,
                minify_filter: glium::uniforms::MinifySamplerFilter::Linear,
                .. Default::default() }));

        target.draw(&vertices, &indices, &self.blit_shader, &uniforms, &params).unwrap();
    }

    /// Call at the start of drawing
    pub fn init(&mut self, display: &glium::Display) {
        let mut target = framebuffer::SimpleFrameBuffer::with_depth_buffer(
            display, &self.buffer, &self.depth);
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        target.clear_depth(1.0);
    }

    /// Draw a geometry buffer.
    pub fn draw(&mut self, display: &glium::Display,
                vertices: Vec<mesh::Vertex>, indices: Vec<u16>) {
        // Render the graphics to a texture to keep the pixels pure and
        // untainted.
        let mut sprite_target = framebuffer::SimpleFrameBuffer::with_depth_buffer(
            display, &self.buffer, &self.depth);
        let mut mesh_buffer = mesh::Buffer::new_shared(self.sprite_shader.clone(), self.atlas.clone());
        let mut triangles = Vec::new();
        for i in 0..(indices.len() / 3) {
            triangles.push([indices[i * 3], indices[i * 3 + 1], indices[i * 3 + 2]]);
        }
        mesh_buffer.push(vertices, triangles);
        mesh_buffer.flush(display, &mut sprite_target);
    }

    /// Show the drawn geometry on screen.
    pub fn show<S>(&mut self, display: &glium::Display, target: &mut S)
        where S: glium::Surface
    {
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        target.clear_depth(1.0);
        let (w, h) = display.get_framebuffer_dimensions();
        // Clip viewport dimensions to even to prevent rounding errors in
        // pixel perfect scaling.
        self.resolution = V2(w & !1, h & !1);
        // Render the texture to screen.
        self.blit_buffer(display, target);
    }

    /// Map screen position (eg. of a mouse cursor) to canvas position.
    pub fn screen_to_canvas(&self, V2(sx, sy): V2<i32>) -> V2<i32> {
        let Rect(V2(rx, ry), V2(rw, rh)) = pixel_perfect(self.size, self.resolution);
        // Transform to device coordinates.
        let sx = sx as f32 * 2.0 / self.resolution.0 as f32 - 1.0;
        let sy = sy as f32 * 2.0 / self.resolution.1 as f32 - 1.0;

        V2(((sx - rx) * self.size.0 as f32 / rw) as i32,
           ((sy - ry) * self.size.1 as f32 / rh) as i32)
    }

    pub fn canvas_pixels(&self) -> image::ImageBuffer<image::Rgb<u8>, Vec<u8>> {
        let mut ret = self.buffer.read::<image::DynamicImage>().to_rgb();

        // Convert to sRGB
        // XXX: Probably horribly slow, can we make OpenGL do this?
        for p in ret.pixels_mut() {
            p.data[0] = (to_srgb(p.data[0] as f32 / 255.0) * 255.0).round() as u8;
            p.data[1] = (to_srgb(p.data[1] as f32 / 255.0) * 255.0).round() as u8;
            p.data[2] = (to_srgb(p.data[2] as f32 / 255.0) * 255.0).round() as u8;
        }

        ret
    }
}

/// A pixel perfect centered and scaled rectangle of resolution dim in a
/// window of size area, mapped to OpenGL device coordinates.
#[inline(always)]
fn pixel_perfect(canvas: V2<u32>, window: V2<u32>) -> Rect<f32> {
    // Scale based on whichever of X or Y axis is the tighter fit.
    let mut scale = (window.0 as f32 / canvas.0 as f32)
        .min(window.1 as f32 / canvas.1 as f32);

    if scale > 1.0 {
        // Snap to pixel scale if more than 1 window pixel per canvas pixel.
        scale = scale.floor();
    }

    let dim = V2((scale * canvas.0 as f32) * 2.0 / window.0 as f32,
                 (scale * canvas.1 as f32) * 2.0 / window.1 as f32);
    let offset = -dim / 2.0;
    Rect(offset, dim)
}

#[inline(always)]
fn preserve_aspect(canvas: V2<u32>, window: V2<u32>) -> Rect<f32> {
    // Scale based on whichever of X or Y axis is the tighter fit.
    let scale = (window.0 as f32 / canvas.0 as f32)
        .min(window.1 as f32 / canvas.1 as f32);

    let dim = V2((scale * canvas.0 as f32) * 2.0 / window.0 as f32,
                 (scale * canvas.1 as f32) * 2.0 / window.1 as f32);
    let offset = -dim / 2.0;
    Rect(offset, dim)
}
<|endoftext|>