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

// ignore-cross-compile

// The general idea of this test is to enumerate all "interesting" expressions and check that
// `parse(print(e)) == e` for all `e`.  Here's what's interesting, for the purposes of this test:
//
//  1. The test focuses on expression nesting, because interactions between different expression
//     types are harder to test manually than single expression types in isolation.
//
//  2. The test only considers expressions of at most two nontrivial nodes.  So it will check `x +
//     x` and `x + (x - x)` but not `(x * x) + (x - x)`.  The assumption here is that the correct
//     handling of an expression might depend on the expression's parent, but doesn't depend on its
//     siblings or any more distant ancestors.
//
// 3. The test only checks certain expression kinds.  The assumption is that similar expression
//    types, such as `if` and `while` or `+` and `-`,  will be handled identically in the printer
//    and parser.  So if all combinations of exprs involving `if` work correctly, then combinations
//    using `while`, `if let`, and so on will likely work as well.

#![feature(rustc_private)]

extern crate syntax;

use syntax::ast::*;
use syntax::codemap::{Spanned, DUMMY_SP, FileName};
use syntax::codemap::FilePathMapping;
use syntax::fold::{self, Folder};
use syntax::parse::{self, ParseSess};
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::util::ThinVec;

fn parse_expr(ps: &ParseSess, src: &str) -> P<Expr> {
    let mut p = parse::new_parser_from_source_str(ps,
                                                  FileName::Custom("expr".to_owned()),
                                                  src.to_owned());
    p.parse_expr().unwrap()
}

// Helper functions for building exprs
fn expr(kind: ExprKind) -> P<Expr> {
    P(Expr {
        id: DUMMY_NODE_ID,
        node: kind,
        span: DUMMY_SP,
        attrs: ThinVec::new(),
    })
}

fn make_x() -> P<Expr> {
    let seg = PathSegment::from_ident(Ident::from_str("x"));
    let path = Path { segments: vec![seg], span: DUMMY_SP };
    expr(ExprKind::Path(None, path))
}

/// Iterate over exprs of depth up to `depth`.  The goal is to explore all "interesting"
/// combinations of expression nesting.  For example, we explore combinations using `if`, but not
/// `while` or `match`, since those should print and parse in much the same way as `if`.
fn iter_exprs(depth: usize, f: &mut FnMut(P<Expr>)) {
    if depth == 0 {
        f(make_x());
        return;
    }

    let mut g = |e| f(expr(e));

    for kind in 0 .. 16 {
        match kind {
            0 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Box(e))),
            1 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))),
            2 => {
                let seg = PathSegment::from_ident(Ident::from_str("x"));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall(
                            seg.clone(), vec![e, make_x()])));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall(
                            seg.clone(), vec![make_x(), e])));
            },
            3 => {
                let op = Spanned { span: DUMMY_SP, node: BinOpKind::Add };
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
            },
            4 => {
                let op = Spanned { span: DUMMY_SP, node: BinOpKind::Mul };
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
            },
            5 => {
                let op = Spanned { span: DUMMY_SP, node: BinOpKind::Shl };
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
            },
            6 => {
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Unary(UnOp::Deref, e)));
            },
            7 => {
                let block = P(Block {
                    stmts: Vec::new(),
                    id: DUMMY_NODE_ID,
                    rules: BlockCheckMode::Default,
                    span: DUMMY_SP,
                    recovered: false,
                });
                iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
            },
            8 => {
                let decl = P(FnDecl {
                    inputs: vec![],
                    output: FunctionRetTy::Default(DUMMY_SP),
                    variadic: false,
                });
                iter_exprs(depth - 1, &mut |e| g(
                        ExprKind::Closure(CaptureBy::Value,
                                          Movability::Movable,
                                          decl.clone(),
                                          e,
                                          DUMMY_SP)));
            },
            9 => {
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x())));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e)));
            },
            10 => {
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f"))));
            },
            11 => {
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
                            Some(e), Some(make_x()), RangeLimits::HalfOpen)));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
                            Some(make_x()), Some(e), RangeLimits::HalfOpen)));
            },
            12 => {
                iter_exprs(depth - 1, &mut |e| g(ExprKind::AddrOf(Mutability::Immutable, e)));
            },
            13 => {
                g(ExprKind::Ret(None));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Ret(Some(e))));
            },
            14 => {
                let path = Path::from_ident(Ident::from_str("S"));
                g(ExprKind::Struct(path, vec![], Some(make_x())));
            },
            15 => {
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e)));
            },
            _ => panic!("bad counter value in iter_exprs"),
        }
    }
}

// Folders for manipulating the placement of `Paren` nodes.  See below for why this is needed.

/// Folder that removes all `ExprKind::Paren` nodes.
struct RemoveParens;

impl Folder for RemoveParens {
    fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
        let e = match e.node {
            ExprKind::Paren(ref inner) => inner.clone(),
            _ => e.clone(),
        };
        e.map(|e| fold::noop_fold_expr(e, self))
    }
}

/// Folder that inserts `ExprKind::Paren` nodes around every `Expr`.
struct AddParens;

impl Folder for AddParens {
    fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
        let e = e.map(|e| fold::noop_fold_expr(e, self));
        P(Expr {
            id: DUMMY_NODE_ID,
            node: ExprKind::Paren(e),
            span: DUMMY_SP,
            attrs: ThinVec::new(),
        })
    }
}

fn main() {
    syntax::with_globals(|| run());
}

fn run() {
    let ps = ParseSess::new(FilePathMapping::empty());

    iter_exprs(2, &mut |e| {
        // If the pretty printer is correct, then `parse(print(e))` should be identical to `e`,
        // modulo placement of `Paren` nodes.
        let printed = pprust::expr_to_string(&e);
        println!("printed: {}", printed);

        let parsed = parse_expr(&ps, &printed);

        // We want to know if `parsed` is structurally identical to `e`, ignoring trivial
        // differences like placement of `Paren`s or the exact ranges of node spans.
        // Unfortunately, there is no easy way to make this comparison.  Instead, we add `Paren`s
        // everywhere we can, then pretty-print.  This should give an unambiguous representation of
        // each `Expr`, and it bypasses nearly all of the parenthesization logic, so we aren't
        // relying on the correctness of the very thing we're testing.
        let e1 = AddParens.fold_expr(RemoveParens.fold_expr(e));
        let text1 = pprust::expr_to_string(&e1);
        let e2 = AddParens.fold_expr(RemoveParens.fold_expr(parsed));
        let text2 = pprust::expr_to_string(&e2);
        assert!(text1 == text2,
                "exprs are not equal:\n  e =      {:?}\n  parsed = {:?}",
                text1, text2);
    });
}
<commit_msg>Fix test using ExprKind::Closure<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-cross-compile

// The general idea of this test is to enumerate all "interesting" expressions and check that
// `parse(print(e)) == e` for all `e`.  Here's what's interesting, for the purposes of this test:
//
//  1. The test focuses on expression nesting, because interactions between different expression
//     types are harder to test manually than single expression types in isolation.
//
//  2. The test only considers expressions of at most two nontrivial nodes.  So it will check `x +
//     x` and `x + (x - x)` but not `(x * x) + (x - x)`.  The assumption here is that the correct
//     handling of an expression might depend on the expression's parent, but doesn't depend on its
//     siblings or any more distant ancestors.
//
// 3. The test only checks certain expression kinds.  The assumption is that similar expression
//    types, such as `if` and `while` or `+` and `-`,  will be handled identically in the printer
//    and parser.  So if all combinations of exprs involving `if` work correctly, then combinations
//    using `while`, `if let`, and so on will likely work as well.

#![feature(rustc_private)]

extern crate syntax;

use syntax::ast::*;
use syntax::codemap::{Spanned, DUMMY_SP, FileName};
use syntax::codemap::FilePathMapping;
use syntax::fold::{self, Folder};
use syntax::parse::{self, ParseSess};
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::util::ThinVec;

fn parse_expr(ps: &ParseSess, src: &str) -> P<Expr> {
    let mut p = parse::new_parser_from_source_str(ps,
                                                  FileName::Custom("expr".to_owned()),
                                                  src.to_owned());
    p.parse_expr().unwrap()
}

// Helper functions for building exprs
fn expr(kind: ExprKind) -> P<Expr> {
    P(Expr {
        id: DUMMY_NODE_ID,
        node: kind,
        span: DUMMY_SP,
        attrs: ThinVec::new(),
    })
}

fn make_x() -> P<Expr> {
    let seg = PathSegment::from_ident(Ident::from_str("x"));
    let path = Path { segments: vec![seg], span: DUMMY_SP };
    expr(ExprKind::Path(None, path))
}

/// Iterate over exprs of depth up to `depth`.  The goal is to explore all "interesting"
/// combinations of expression nesting.  For example, we explore combinations using `if`, but not
/// `while` or `match`, since those should print and parse in much the same way as `if`.
fn iter_exprs(depth: usize, f: &mut FnMut(P<Expr>)) {
    if depth == 0 {
        f(make_x());
        return;
    }

    let mut g = |e| f(expr(e));

    for kind in 0 .. 16 {
        match kind {
            0 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Box(e))),
            1 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))),
            2 => {
                let seg = PathSegment::from_ident(Ident::from_str("x"));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall(
                            seg.clone(), vec![e, make_x()])));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall(
                            seg.clone(), vec![make_x(), e])));
            },
            3 => {
                let op = Spanned { span: DUMMY_SP, node: BinOpKind::Add };
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
            },
            4 => {
                let op = Spanned { span: DUMMY_SP, node: BinOpKind::Mul };
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
            },
            5 => {
                let op = Spanned { span: DUMMY_SP, node: BinOpKind::Shl };
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
            },
            6 => {
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Unary(UnOp::Deref, e)));
            },
            7 => {
                let block = P(Block {
                    stmts: Vec::new(),
                    id: DUMMY_NODE_ID,
                    rules: BlockCheckMode::Default,
                    span: DUMMY_SP,
                    recovered: false,
                });
                iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
            },
            8 => {
                let decl = P(FnDecl {
                    inputs: vec![],
                    output: FunctionRetTy::Default(DUMMY_SP),
                    variadic: false,
                });
                iter_exprs(depth - 1, &mut |e| g(
                        ExprKind::Closure(CaptureBy::Value,
                                          IsAsync::NotAsync,
                                          Movability::Movable,
                                          decl.clone(),
                                          e,
                                          DUMMY_SP)));
            },
            9 => {
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x())));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e)));
            },
            10 => {
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f"))));
            },
            11 => {
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
                            Some(e), Some(make_x()), RangeLimits::HalfOpen)));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
                            Some(make_x()), Some(e), RangeLimits::HalfOpen)));
            },
            12 => {
                iter_exprs(depth - 1, &mut |e| g(ExprKind::AddrOf(Mutability::Immutable, e)));
            },
            13 => {
                g(ExprKind::Ret(None));
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Ret(Some(e))));
            },
            14 => {
                let path = Path::from_ident(Ident::from_str("S"));
                g(ExprKind::Struct(path, vec![], Some(make_x())));
            },
            15 => {
                iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e)));
            },
            _ => panic!("bad counter value in iter_exprs"),
        }
    }
}

// Folders for manipulating the placement of `Paren` nodes.  See below for why this is needed.

/// Folder that removes all `ExprKind::Paren` nodes.
struct RemoveParens;

impl Folder for RemoveParens {
    fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
        let e = match e.node {
            ExprKind::Paren(ref inner) => inner.clone(),
            _ => e.clone(),
        };
        e.map(|e| fold::noop_fold_expr(e, self))
    }
}

/// Folder that inserts `ExprKind::Paren` nodes around every `Expr`.
struct AddParens;

impl Folder for AddParens {
    fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
        let e = e.map(|e| fold::noop_fold_expr(e, self));
        P(Expr {
            id: DUMMY_NODE_ID,
            node: ExprKind::Paren(e),
            span: DUMMY_SP,
            attrs: ThinVec::new(),
        })
    }
}

fn main() {
    syntax::with_globals(|| run());
}

fn run() {
    let ps = ParseSess::new(FilePathMapping::empty());

    iter_exprs(2, &mut |e| {
        // If the pretty printer is correct, then `parse(print(e))` should be identical to `e`,
        // modulo placement of `Paren` nodes.
        let printed = pprust::expr_to_string(&e);
        println!("printed: {}", printed);

        let parsed = parse_expr(&ps, &printed);

        // We want to know if `parsed` is structurally identical to `e`, ignoring trivial
        // differences like placement of `Paren`s or the exact ranges of node spans.
        // Unfortunately, there is no easy way to make this comparison.  Instead, we add `Paren`s
        // everywhere we can, then pretty-print.  This should give an unambiguous representation of
        // each `Expr`, and it bypasses nearly all of the parenthesization logic, so we aren't
        // relying on the correctness of the very thing we're testing.
        let e1 = AddParens.fold_expr(RemoveParens.fold_expr(e));
        let text1 = pprust::expr_to_string(&e1);
        let e2 = AddParens.fold_expr(RemoveParens.fold_expr(parsed));
        let text2 = pprust::expr_to_string(&e2);
        assert!(text1 == text2,
                "exprs are not equal:\n  e =      {:?}\n  parsed = {:?}",
                text1, text2);
    });
}
<|endoftext|>


<commit_before>use core::vec;

// A generic tree datatype.
//
// TODO: Use traits.

pub type Tree<T> = {
    mut parent: Option<T>,
    mut first_child: Option<T>,
    mut last_child: Option<T>,
    mut prev_sibling: Option<T>,
    mut next_sibling: Option<T>
};

pub trait ReadMethods<T> {
    fn with_tree_fields<R>(&T, f: fn(&Tree<T>) -> R) -> R;
}

pub trait WriteMethods<T> {
    fn with_tree_fields<R>(&T, f: fn(&Tree<T>) -> R) -> R;
    pure fn eq(&T, &T) -> bool;
}

pub fn each_child<T:Copy,O:ReadMethods<T>>(ops: &O, node: &T, f: fn(&T) -> bool) {
    let mut p = ops.with_tree_fields(node, |f| f.first_child);
    loop {
        match copy p {
          None => { return; }
          Some(ref c) => {
            if !f(c) { return; }
            p = ops.with_tree_fields(c, |f| f.next_sibling);
          }
        }
    }
}

pub fn empty<T>() -> Tree<T> {
    {mut parent: None,
     mut first_child: None,
     mut last_child: None,
     mut prev_sibling: None,
     mut next_sibling: None}
}

pub fn add_child<T:Copy,O:WriteMethods<T>>(ops: &O, parent: T, child: T) {
    assert !ops.eq(&parent, &child);

    ops.with_tree_fields(&child, |child_tf| {
        match child_tf.parent {
          Some(_) => { fail ~"Already has a parent"; }
          None => { child_tf.parent = Some(parent); }
        }

        assert child_tf.prev_sibling.is_none();
        assert child_tf.next_sibling.is_none();

        ops.with_tree_fields(&parent, |parent_tf| {
            match copy parent_tf.last_child {
              None => {
                parent_tf.first_child = Some(child);
              }
              Some(lc) => {
                ops.with_tree_fields(&lc, |lc_tf| {
                    assert lc_tf.next_sibling.is_none();
                    lc_tf.next_sibling = Some(child);
                });
                child_tf.prev_sibling = Some(lc);
              }
            }

            parent_tf.last_child = Some(child);
        });
    });
}

pub fn remove_child<T:Copy,O:WriteMethods<T>>(ops: &O, parent: T, child: T) {
    do ops.with_tree_fields(&child) |child_tf| {
        match copy child_tf.parent {
            None => { fail ~"Not a child"; }
            Some(parent_n) => {
                assert ops.eq(&parent, &parent_n);

                // adjust parent fields
                do ops.with_tree_fields(&parent) |parent_tf| {
                    match copy parent_tf.first_child {
                        None => { fail ~"parent had no first child??" },
                        Some(first_child) if ops.eq(&child, &first_child) => {
                            parent_tf.first_child = child_tf.next_sibling;
                        },
                        Some(_) => {}
                    };

                    match copy parent_tf.last_child {
                        None => { fail ~"parent had no last child??" },
                        Some(last_child) if ops.eq(&child, &last_child) => {
                            parent_tf.last_child = child_tf.prev_sibling;
                        },
                        Some(_) => {}
                    }
                }
            }
        }

        // adjust siblings
        match child_tf.prev_sibling {
            None => {},
            Some(_) => {
                do ops.with_tree_fields(&child_tf.prev_sibling.get()) |prev_tf| {
                    prev_tf.next_sibling = child_tf.next_sibling;
                }
            }
        }
        match child_tf.next_sibling {
            None => {},
            Some(_) => {
                do ops.with_tree_fields(&child_tf.next_sibling.get()) |next_tf| {
                    next_tf.prev_sibling = child_tf.prev_sibling;
                }
            }
        }

        // clear child
        child_tf.parent = None;
        child_tf.next_sibling = None;
        child_tf.prev_sibling = None;
    }
}

pub fn get_parent<T:Copy,O:ReadMethods<T>>(ops: &O, node: &T) -> Option<T> {
    ops.with_tree_fields(node, |tf| tf.parent)
}

#[cfg(test)]
mod test {
    enum dummy = {
        fields: Tree<@dummy>,
        value: uint
    };

    enum dtree { dtree }

    impl dtree : ReadMethods<@dummy> {
        fn with_tree_fields<R>(d: &@dummy, f: fn(&Tree<@dummy>) -> R) -> R {
            f(&d.fields)
        }
    }

    impl dtree : WriteMethods<@dummy> {
        fn with_tree_fields<R>(d: &@dummy, f: fn(&Tree<@dummy>) -> R) -> R {
            f(&d.fields)
        }
        pure fn eq(a: &@dummy, b: &@dummy) -> bool { core::box::ptr_eq(*a, *b) }
    }

    fn new_dummy(v: uint) -> @dummy {
        @dummy({fields: empty(), value: v})
    }

    fn parent_with_3_children() -> {p: @dummy, children: ~[@dummy]} {
        let children = ~[new_dummy(0u),
                         new_dummy(1u),
                         new_dummy(2u)];
        let p = new_dummy(3u);

        for vec::each(children) |c| {
            add_child(&dtree, p, *c);
        }

        return {p: p, children: children};
    }

    #[test]
    fn add_child_0() {
        let {p, children} = parent_with_3_children();
        let mut i = 0u;
        for each_child(&dtree, &p) |c| {
            assert c.value == i;
            i += 1u;
        }
        assert i == children.len();
    }

    #[test]
    fn add_child_break() {
        let {p, _} = parent_with_3_children();
        let mut i = 0u;
        for each_child(&dtree, &p) |_c| {
            i += 1u;
            break;
        }
        assert i == 1u;
    }

    #[test]
    fn remove_first_child() {
        let {p, children} = parent_with_3_children();
        remove_child(&dtree, p, children[0]);

        let mut i = 0;
        for each_child(&dtree, &p) |_c| {
            i += 1;
        }
        assert i == 2;
    }

    #[test]
    fn remove_last_child() {
        let {p, children} = parent_with_3_children();
        remove_child(&dtree, p, children[2]);

        let mut i = 0;
        for each_child(&dtree, &p) |_c| {
            i += 1;
        }
        assert i == 2;
    }

    #[test]
    fn remove_middle_child() {
        let {p, children} = parent_with_3_children();
        remove_child(&dtree, p, children[1]);

        let mut i = 0;
        for each_child(&dtree, &p) |_c| {
            i += 1;
        }
        assert i == 2;
    }

    #[test]
    fn remove_all_child() {
        let {p, children} = parent_with_3_children();
        remove_child(&dtree, p, children[0]);
        remove_child(&dtree, p, children[1]);
        remove_child(&dtree, p, children[2]);

        let mut i = 0;
        for each_child(&dtree, &p) |_c| {
            i += 1;
        }
        assert i == 0;
    }
}
<commit_msg>Add some helper methods to util::tree for accessing tree fields (it wasn't possible before due to multiple with_tree_fields implementations)<commit_after>use core::vec;

// A generic tree datatype.
//
// TODO: Use traits.

pub type Tree<T> = {
    mut parent: Option<T>,
    mut first_child: Option<T>,
    mut last_child: Option<T>,
    mut prev_sibling: Option<T>,
    mut next_sibling: Option<T>
};

pub trait ReadMethods<T> {
    fn with_tree_fields<R>(&T, f: fn(&Tree<T>) -> R) -> R;
}

pub trait WriteMethods<T> {
    fn with_tree_fields<R>(&T, f: fn(&Tree<T>) -> R) -> R;
    pure fn eq(&T, &T) -> bool;
}

pub fn each_child<T:Copy,O:ReadMethods<T>>(ops: &O, node: &T, f: fn(&T) -> bool) {
    let mut p = ops.with_tree_fields(node, |f| f.first_child);
    loop {
        match copy p {
          None => { return; }
          Some(ref c) => {
            if !f(c) { return; }
            p = ops.with_tree_fields(c, |f| f.next_sibling);
          }
        }
    }
}

pub fn first_child<T:Copy,O:ReadMethods<T>>(ops: &O, node: &T) -> Option<T> {
    ops.with_tree_fields(node, |tf| tf.first_child)
}

pub fn last_child<T:Copy,O:ReadMethods<T>>(ops: &O, node: &T) -> Option<T> {
    ops.with_tree_fields(node, |tf| tf.last_child)
}

pub fn next_sibling<T:Copy,O:ReadMethods<T>>(ops: &O, node: &T) -> Option<T> {
    ops.with_tree_fields(node, |tf| tf.next_sibling)
}

pub fn prev_sibling<T:Copy,O:ReadMethods<T>>(ops: &O, node: &T) -> Option<T> {
    ops.with_tree_fields(node, |tf| tf.prev_sibling)
}

pub fn parent<T:Copy,O:ReadMethods<T>>(ops: &O, node: &T) -> Option<T> {
    ops.with_tree_fields(node, |tf| tf.parent)
}

pub fn empty<T>() -> Tree<T> {
    {mut parent: None,
     mut first_child: None,
     mut last_child: None,
     mut prev_sibling: None,
     mut next_sibling: None}
}

pub fn add_child<T:Copy,O:WriteMethods<T>>(ops: &O, parent: T, child: T) {
    assert !ops.eq(&parent, &child);

    ops.with_tree_fields(&child, |child_tf| {
        match child_tf.parent {
          Some(_) => { fail ~"Already has a parent"; }
          None => { child_tf.parent = Some(parent); }
        }

        assert child_tf.prev_sibling.is_none();
        assert child_tf.next_sibling.is_none();

        ops.with_tree_fields(&parent, |parent_tf| {
            match copy parent_tf.last_child {
              None => {
                parent_tf.first_child = Some(child);
              }
              Some(lc) => {
                ops.with_tree_fields(&lc, |lc_tf| {
                    assert lc_tf.next_sibling.is_none();
                    lc_tf.next_sibling = Some(child);
                });
                child_tf.prev_sibling = Some(lc);
              }
            }

            parent_tf.last_child = Some(child);
        });
    });
}

pub fn remove_child<T:Copy,O:WriteMethods<T>>(ops: &O, parent: T, child: T) {
    do ops.with_tree_fields(&child) |child_tf| {
        match copy child_tf.parent {
            None => { fail ~"Not a child"; }
            Some(parent_n) => {
                assert ops.eq(&parent, &parent_n);

                // adjust parent fields
                do ops.with_tree_fields(&parent) |parent_tf| {
                    match copy parent_tf.first_child {
                        None => { fail ~"parent had no first child??" },
                        Some(first_child) if ops.eq(&child, &first_child) => {
                            parent_tf.first_child = child_tf.next_sibling;
                        },
                        Some(_) => {}
                    };

                    match copy parent_tf.last_child {
                        None => { fail ~"parent had no last child??" },
                        Some(last_child) if ops.eq(&child, &last_child) => {
                            parent_tf.last_child = child_tf.prev_sibling;
                        },
                        Some(_) => {}
                    }
                }
            }
        }

        // adjust siblings
        match child_tf.prev_sibling {
            None => {},
            Some(_) => {
                do ops.with_tree_fields(&child_tf.prev_sibling.get()) |prev_tf| {
                    prev_tf.next_sibling = child_tf.next_sibling;
                }
            }
        }
        match child_tf.next_sibling {
            None => {},
            Some(_) => {
                do ops.with_tree_fields(&child_tf.next_sibling.get()) |next_tf| {
                    next_tf.prev_sibling = child_tf.prev_sibling;
                }
            }
        }

        // clear child
        child_tf.parent = None;
        child_tf.next_sibling = None;
        child_tf.prev_sibling = None;
    }
}

pub fn get_parent<T:Copy,O:ReadMethods<T>>(ops: &O, node: &T) -> Option<T> {
    ops.with_tree_fields(node, |tf| tf.parent)
}

#[cfg(test)]
mod test {
    enum dummy = {
        fields: Tree<@dummy>,
        value: uint
    };

    enum dtree { dtree }

    impl dtree : ReadMethods<@dummy> {
        fn with_tree_fields<R>(d: &@dummy, f: fn(&Tree<@dummy>) -> R) -> R {
            f(&d.fields)
        }
    }

    impl dtree : WriteMethods<@dummy> {
        fn with_tree_fields<R>(d: &@dummy, f: fn(&Tree<@dummy>) -> R) -> R {
            f(&d.fields)
        }
        pure fn eq(a: &@dummy, b: &@dummy) -> bool { core::box::ptr_eq(*a, *b) }
    }

    fn new_dummy(v: uint) -> @dummy {
        @dummy({fields: empty(), value: v})
    }

    fn parent_with_3_children() -> {p: @dummy, children: ~[@dummy]} {
        let children = ~[new_dummy(0u),
                         new_dummy(1u),
                         new_dummy(2u)];
        let p = new_dummy(3u);

        for vec::each(children) |c| {
            add_child(&dtree, p, *c);
        }

        return {p: p, children: children};
    }

    #[test]
    fn add_child_0() {
        let {p, children} = parent_with_3_children();
        let mut i = 0u;
        for each_child(&dtree, &p) |c| {
            assert c.value == i;
            i += 1u;
        }
        assert i == children.len();
    }

    #[test]
    fn add_child_break() {
        let {p, _} = parent_with_3_children();
        let mut i = 0u;
        for each_child(&dtree, &p) |_c| {
            i += 1u;
            break;
        }
        assert i == 1u;
    }

    #[test]
    fn remove_first_child() {
        let {p, children} = parent_with_3_children();
        remove_child(&dtree, p, children[0]);

        let mut i = 0;
        for each_child(&dtree, &p) |_c| {
            i += 1;
        }
        assert i == 2;
    }

    #[test]
    fn remove_last_child() {
        let {p, children} = parent_with_3_children();
        remove_child(&dtree, p, children[2]);

        let mut i = 0;
        for each_child(&dtree, &p) |_c| {
            i += 1;
        }
        assert i == 2;
    }

    #[test]
    fn remove_middle_child() {
        let {p, children} = parent_with_3_children();
        remove_child(&dtree, p, children[1]);

        let mut i = 0;
        for each_child(&dtree, &p) |_c| {
            i += 1;
        }
        assert i == 2;
    }

    #[test]
    fn remove_all_child() {
        let {p, children} = parent_with_3_children();
        remove_child(&dtree, p, children[0]);
        remove_child(&dtree, p, children[1]);
        remove_child(&dtree, p, children[2]);

        let mut i = 0;
        for each_child(&dtree, &p) |_c| {
            i += 1;
        }
        assert i == 0;
    }
}
<|endoftext|>


<commit_before>use tasks::RunsTask;
use bot::BotEnv;
use commands::tag::Tagger;
use database::models::TagQueue;

use chrono::Duration;

use diesel::prelude::*;

use std::sync::Arc;
use std::thread;

pub struct TagQueueTask {
  pub next_sleep: i64
}

impl Default for TagQueueTask {
  fn default() -> Self {
    TagQueueTask { next_sleep: 30 }
  }
}

impl RunsTask for TagQueueTask {
  fn start(mut self, env: Arc<BotEnv>) {
    loop {
      thread::sleep(Duration::seconds(self.next_sleep).to_std().unwrap());
      self.next_sleep = Duration::minutes(30).num_seconds();
      info!("Checking tag queue");
      let mut queue: Vec<TagQueue> = match ::bot::CONNECTION.with(|c| {
        use database::schema::tag_queue::dsl;
        dsl::tag_queue.load(c)
      }) {
        Ok(t) => t,
        Err(e) => {
          warn!("could not load tag queue: {}", e);
          continue;
        }
      };
      let len = queue.len();
      if len == 0 {
        info!("No queued tags");
        continue;
      } else {
        info!("{} queued tag{}", len, if len == 1 { "" } else { "s" });
      }
      queue.retain(|item| {
        match Tagger::search_tag(
          env.as_ref(),
          (*item.user_id).into(),
          (*item.server_id).into(),
          &item.server,
          &item.character,
          false
        ) {
          Ok(None) => true,
          _ => false
        }
      });
      let diff = len - queue.len();
      info!("Successfully tagged {}/{} queued tags", diff, len);
      for remove in queue {
        if let Err(e) = ::bot::CONNECTION.with(|c| ::diesel::delete(&remove).execute(c)) {
          warn!("could not remove item from queue after successful tagging: {}", e);
        }
      }
    }
  }
}
<commit_msg>fix: display correct number<commit_after>use tasks::RunsTask;
use bot::BotEnv;
use commands::tag::Tagger;
use database::models::TagQueue;

use chrono::Duration;

use diesel::prelude::*;

use std::sync::Arc;
use std::thread;

pub struct TagQueueTask {
  pub next_sleep: i64
}

impl Default for TagQueueTask {
  fn default() -> Self {
    TagQueueTask { next_sleep: 30 }
  }
}

impl RunsTask for TagQueueTask {
  fn start(mut self, env: Arc<BotEnv>) {
    loop {
      thread::sleep(Duration::seconds(self.next_sleep).to_std().unwrap());
      self.next_sleep = Duration::minutes(30).num_seconds();
      info!("Checking tag queue");
      let mut queue: Vec<TagQueue> = match ::bot::CONNECTION.with(|c| {
        use database::schema::tag_queue::dsl;
        dsl::tag_queue.load(c)
      }) {
        Ok(t) => t,
        Err(e) => {
          warn!("could not load tag queue: {}", e);
          continue;
        }
      };
      let len = queue.len();
      if len == 0 {
        info!("No queued tags");
        continue;
      } else {
        info!("{} queued tag{}", len, if len == 1 { "" } else { "s" });
      }
      queue.retain(|item| {
        match Tagger::search_tag(
          env.as_ref(),
          (*item.user_id).into(),
          (*item.server_id).into(),
          &item.server,
          &item.character,
          false
        ) {
          Ok(None) => true,
          _ => false
        }
      });
      info!("Successfully tagged {}/{} queued tags", queue.len(), len);
      for remove in queue {
        if let Err(e) = ::bot::CONNECTION.with(|c| ::diesel::delete(&remove).execute(c)) {
          warn!("could not remove item from queue after successful tagging: {}", e);
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>mod error;

pub use self::error::{Error, Result};
use counters::Counters;
use mapper::{self, Mapper, NewTransaction};
use utils;

pub const TAG_LENGTH: usize = 27;
const NULL_HASH: &str = "999999999999999999999999999999999999999999999999999999999999999999999999999999999";

#[derive(Debug)]
pub struct Transaction<'a> {
  hash: &'a str,
  address_hash: &'a str,
  value: i64,
  tag: &'a str,
  timestamp: i64,
  current_index: i32,
  last_index: i32,
  bundle_hash: &'a str,
  trunk_hash: &'a str,
  branch_hash: &'a str,
  is_milestone: bool,
  solid: bool,
}

pub type ApproveIds = Option<Vec<u64>>;
pub type SolidHash = Option<String>;

impl<'a> Transaction<'a> {
  pub fn parse(
    source: &'a str,
    milestone_address: &str,
    milestone_start_index: &str,
  ) -> Result<Self> {
    let chunks: Vec<&'a str> = source.split(' ').collect();
    let hash = chunks[1];
    let address_hash = chunks[2];
    let value = chunks[3].parse()?;
    let tag = &chunks[4][..TAG_LENGTH];
    let timestamp = chunks[5].parse()?;
    let current_index = chunks[6].parse()?;
    let last_index = chunks[7].parse()?;
    let bundle_hash = chunks[8];
    let trunk_hash = chunks[9];
    let branch_hash = chunks[10];
    let is_milestone = address_hash == milestone_address;
    let solid = is_milestone && tag == milestone_start_index;
    Ok(Self {
      hash,
      address_hash,
      value,
      tag,
      timestamp,
      current_index,
      last_index,
      bundle_hash,
      trunk_hash,
      branch_hash,
      is_milestone,
      solid,
    })
  }

  pub fn approve(mapper: &mut Mapper, mut ids: Vec<u64>) -> Result<()> {
    let (timestamp, mut counter) = (utils::milliseconds_since_epoch()?, 0);
    while let Some(id) = ids.pop() {
      let record = mapper.select_transaction_by_id(id)?;
      if record.mst_a.unwrap_or(false) {
        continue;
      }
      let id_trunk = record.id_trunk.unwrap_or(0);
      let id_branch = record.id_branch.unwrap_or(0);
      if id_trunk != 0 {
        ids.push(id_trunk);
      }
      if id_branch != 0 {
        ids.push(id_branch);
      }
      if let Ok(0) = record.current_idx {
        if let Ok(id_bundle) = record.id_bundle {
          mapper.update_bundle(id_bundle, timestamp)?;
        }
      }
      mapper.approve_transaction(id)?;
      counter += 1;
    }
    if counter > 0 {
      mapper.subtanble_confirmation_event(timestamp, counter)?;
    }
    Ok(())
  }

  pub fn solidate(mapper: &mut Mapper, hash: &str) -> Result<()> {
    let (timestamp, mut counter) = (utils::milliseconds_since_epoch()?, 0);
    let id = mapper
      .select_transaction_by_hash(hash)?
      .ok_or(mapper::Error::RecordNotFound)?
      .id_tx?;
    let mut nodes = vec![(id, Some(0))];
    while let Some((parent_id, parent_height)) = nodes.pop() {
      let (mut trunk, mut branch) = (Vec::new(), Vec::new());
      for record in mapper.select_child_transactions(parent_id)? {
        if record.id_trunk? == parent_id {
          trunk.push((record.id_tx?, record.height?, record.solid?));
        } else if record.id_branch? == parent_id {
          branch.push((record.id_tx?, record.height?, record.solid?));
        }
      }
      Self::solidate_nodes(mapper, &mut nodes, &trunk, 0b10, parent_height)?;
      Self::solidate_nodes(mapper, &mut nodes, &branch, 0b01, None)?;
      counter += trunk.len() as i32;
      counter += branch.len() as i32;
    }
    if counter > 0 {
      mapper.subtangle_solidation_event(timestamp, counter)?;
    }
    Ok(())
  }

  pub fn process(
    &mut self,
    mapper: &mut Mapper,
    counters: &Counters,
  ) -> Result<(ApproveIds, SolidHash)> {
    let result = mapper.select_transaction_by_hash(self.hash)?;
    let new_record = if let Some(record) = result {
      if record.id_trunk.unwrap_or(0) != 0 &&
        record.id_branch.unwrap_or(0) != 0
      {
        return Ok((None, None));
      }
      false
    } else {
      true
    };
    let timestamp = utils::milliseconds_since_epoch()?;
    let (id_trunk, trunk_solid) =
      Self::check_node(mapper, counters, self.trunk_hash)?;
    let (id_branch, branch_solid) =
      Self::check_node(mapper, counters, self.branch_hash)?;
    let id_address = mapper.fetch_address(counters, self.address_hash)?;
    let id_bundle = mapper
      .fetch_bundle(counters, timestamp, self.bundle_hash, self.last_index)?;
    let solid = if self.solid {
      0b11
    } else {
      (if trunk_solid == 0b11 { 0b10 } else { 0b00 }) |
        (if branch_solid == 0b11 { 0b01 } else { 0b00 })
    };
    let record = NewTransaction {
      hash: self.hash,
      id_trunk: id_trunk,
      id_branch: id_branch,
      id_address: id_address,
      id_bundle: id_bundle,
      tag: self.tag,
      value: self.value,
      timestamp: self.timestamp,
      current_idx: self.current_index,
      last_idx: self.last_index,
      is_mst: self.is_milestone,
      mst_a: self.is_milestone,
      solid: solid,
    };
    if new_record {
      mapper.insert_transaction(counters, record)?;
    } else {
      mapper.update_transaction(record)?;
    }
    if solid != 0b11 {
      mapper.unsolid_transaction_event(timestamp)?;
    }
    mapper.new_transaction_received_event(timestamp)?;
    let approve_ids = if self.is_milestone {
      mapper.milestone_received_event(timestamp)?;
      Some(vec![id_trunk, id_branch])
    } else {
      None
    };
    let solid_hash = if self.solid && !new_record {
      Some(self.hash.to_owned())
    } else {
      None
    };
    Ok((approve_ids, solid_hash))
  }

  fn check_node(
    mapper: &mut Mapper,
    counters: &Counters,
    hash: &str,
  ) -> Result<(u64, u8)> {
    match mapper.select_transaction_by_hash(hash)? {
      Some(record) => {
        let id_tx = record.id_tx?;
        mapper.direct_approve_transaction(id_tx)?;
        Ok((id_tx, record.solid?))
      }
      None => {
        let solid = if hash == NULL_HASH { 0b11 } else { 0b00 };
        Ok((
          mapper
            .insert_transaction_placeholder(counters, hash, solid)?,
          solid,
        ))
      }
    }
  }

  fn solidate_nodes(
    mapper: &mut Mapper,
    nodes: &mut Vec<(u64, Option<i32>)>,
    ids: &[(u64, i32, u8)],
    solid: u8,
    height: Option<i32>,
  ) -> Result<()> {
    for &(id, mut node_height, mut node_solid) in ids {
      if node_solid & solid != 0b00 {
        continue;
      }
      node_solid |= solid;
      match height {
        Some(height) => {
          node_height = height + 1;
          mapper
            .solidate_trunk_transaction(id, node_height, node_solid)?;
        }
        None => {
          mapper.solidate_branch_transaction(id, node_solid)?;
        }
      }
      if node_solid == 0b11 {
        let node_height = if node_height > 0 {
          Some(node_height)
        } else {
          None
        };
        nodes.push((id, node_height));
      }
    }
    Ok(())
  }
}
<commit_msg>Fixed solidity check<commit_after>mod error;

pub use self::error::{Error, Result};
use counters::Counters;
use mapper::{self, Mapper, NewTransaction};
use utils;

pub const TAG_LENGTH: usize = 27;
const NULL_HASH: &str = "999999999999999999999999999999999999999999999999999999999999999999999999999999999";

#[derive(Debug)]
pub struct Transaction<'a> {
  hash: &'a str,
  address_hash: &'a str,
  value: i64,
  tag: &'a str,
  timestamp: i64,
  current_index: i32,
  last_index: i32,
  bundle_hash: &'a str,
  trunk_hash: &'a str,
  branch_hash: &'a str,
  is_milestone: bool,
  solid: u8,
}

pub type ApproveIds = Option<Vec<u64>>;
pub type SolidHash = Option<String>;

impl<'a> Transaction<'a> {
  pub fn parse(
    source: &'a str,
    milestone_address: &str,
    milestone_start_index: &str,
  ) -> Result<Self> {
    let chunks: Vec<&'a str> = source.split(' ').collect();
    let hash = chunks[1];
    let address_hash = chunks[2];
    let value = chunks[3].parse()?;
    let tag = &chunks[4][..TAG_LENGTH];
    let timestamp = chunks[5].parse()?;
    let current_index = chunks[6].parse()?;
    let last_index = chunks[7].parse()?;
    let bundle_hash = chunks[8];
    let trunk_hash = chunks[9];
    let branch_hash = chunks[10];
    let is_milestone = address_hash == milestone_address;
    let solid = if is_milestone && tag == milestone_start_index {
      0b11
    } else {
      0b00
    };
    Ok(Self {
      hash,
      address_hash,
      value,
      tag,
      timestamp,
      current_index,
      last_index,
      bundle_hash,
      trunk_hash,
      branch_hash,
      is_milestone,
      solid,
    })
  }

  pub fn approve(mapper: &mut Mapper, mut ids: Vec<u64>) -> Result<()> {
    let (timestamp, mut counter) = (utils::milliseconds_since_epoch()?, 0);
    while let Some(id) = ids.pop() {
      let record = mapper.select_transaction_by_id(id)?;
      if record.mst_a.unwrap_or(false) {
        continue;
      }
      let id_trunk = record.id_trunk.unwrap_or(0);
      let id_branch = record.id_branch.unwrap_or(0);
      if id_trunk != 0 {
        ids.push(id_trunk);
      }
      if id_branch != 0 {
        ids.push(id_branch);
      }
      if let Ok(0) = record.current_idx {
        if let Ok(id_bundle) = record.id_bundle {
          mapper.update_bundle(id_bundle, timestamp)?;
        }
      }
      mapper.approve_transaction(id)?;
      counter += 1;
    }
    if counter > 0 {
      mapper.subtanble_confirmation_event(timestamp, counter)?;
    }
    Ok(())
  }

  pub fn solidate(mapper: &mut Mapper, hash: &str) -> Result<()> {
    let (timestamp, mut counter) = (utils::milliseconds_since_epoch()?, 0);
    let id = mapper
      .select_transaction_by_hash(hash)?
      .ok_or(mapper::Error::RecordNotFound)?
      .id_tx?;
    let mut nodes = vec![(id, Some(0))];
    while let Some((parent_id, parent_height)) = nodes.pop() {
      let (mut trunk, mut branch) = (Vec::new(), Vec::new());
      for record in mapper.select_child_transactions(parent_id)? {
        if record.id_trunk? == parent_id {
          trunk.push((record.id_tx?, record.height?, record.solid?));
        } else if record.id_branch? == parent_id {
          branch.push((record.id_tx?, record.height?, record.solid?));
        }
      }
      Self::solidate_nodes(mapper, &mut nodes, &trunk, 0b10, parent_height)?;
      Self::solidate_nodes(mapper, &mut nodes, &branch, 0b01, None)?;
      counter += trunk.len() as i32;
      counter += branch.len() as i32;
    }
    if counter > 0 {
      mapper.subtangle_solidation_event(timestamp, counter)?;
    }
    Ok(())
  }

  pub fn process(
    &mut self,
    mapper: &mut Mapper,
    counters: &Counters,
  ) -> Result<(ApproveIds, SolidHash)> {
    let result = mapper.select_transaction_by_hash(self.hash)?;
    let new_record = if let Some(record) = result {
      if record.id_trunk.unwrap_or(0) != 0 &&
        record.id_branch.unwrap_or(0) != 0
      {
        return Ok((None, None));
      }
      false
    } else {
      true
    };
    let timestamp = utils::milliseconds_since_epoch()?;
    let (id_trunk, trunk_solid) =
      Self::check_node(mapper, counters, self.trunk_hash)?;
    let (id_branch, branch_solid) =
      Self::check_node(mapper, counters, self.branch_hash)?;
    let id_address = mapper.fetch_address(counters, self.address_hash)?;
    let id_bundle = mapper
      .fetch_bundle(counters, timestamp, self.bundle_hash, self.last_index)?;
    if trunk_solid == 0b11 {
      self.solid |= 0b10;
    }
    if branch_solid == 0b11 {
      self.solid |= 0b01
    }
    let record = NewTransaction {
      hash: self.hash,
      id_trunk: id_trunk,
      id_branch: id_branch,
      id_address: id_address,
      id_bundle: id_bundle,
      tag: self.tag,
      value: self.value,
      timestamp: self.timestamp,
      current_idx: self.current_index,
      last_idx: self.last_index,
      is_mst: self.is_milestone,
      mst_a: self.is_milestone,
      solid: self.solid,
    };
    if new_record {
      mapper.insert_transaction(counters, record)?;
    } else {
      mapper.update_transaction(record)?;
    }
    if self.solid != 0b11 {
      mapper.unsolid_transaction_event(timestamp)?;
    }
    mapper.new_transaction_received_event(timestamp)?;
    let approve_ids = if self.is_milestone {
      mapper.milestone_received_event(timestamp)?;
      Some(vec![id_trunk, id_branch])
    } else {
      None
    };
    let solid_hash = if self.solid == 0b11 && !new_record {
      Some(self.hash.to_owned())
    } else {
      None
    };
    Ok((approve_ids, solid_hash))
  }

  fn check_node(
    mapper: &mut Mapper,
    counters: &Counters,
    hash: &str,
  ) -> Result<(u64, u8)> {
    match mapper.select_transaction_by_hash(hash)? {
      Some(record) => {
        let id_tx = record.id_tx?;
        mapper.direct_approve_transaction(id_tx)?;
        Ok((id_tx, record.solid?))
      }
      None => {
        let solid = if hash == NULL_HASH { 0b11 } else { 0b00 };
        Ok((
          mapper
            .insert_transaction_placeholder(counters, hash, solid)?,
          solid,
        ))
      }
    }
  }

  fn solidate_nodes(
    mapper: &mut Mapper,
    nodes: &mut Vec<(u64, Option<i32>)>,
    ids: &[(u64, i32, u8)],
    solid: u8,
    height: Option<i32>,
  ) -> Result<()> {
    for &(id, mut node_height, mut node_solid) in ids {
      if node_solid & solid != 0b00 {
        continue;
      }
      node_solid |= solid;
      match height {
        Some(height) => {
          node_height = height + 1;
          mapper
            .solidate_trunk_transaction(id, node_height, node_solid)?;
        }
        None => {
          mapper.solidate_branch_transaction(id, node_solid)?;
        }
      }
      if node_solid == 0b11 {
        let node_height = if node_height > 0 {
          Some(node_height)
        } else {
          None
        };
        nodes.push((id, node_height));
      }
    }
    Ok(())
  }
}
<|endoftext|>


<commit_before>// This code is heavily inspired by hoedown.

//
// Performance observations:
//
// Note that buf.head() == Some(&ch) is much faster than buf[0] == ch.
//

static SP: u8 = ' ' as u8;
static NL: u8 = '\n' as u8;
static CR: u8 = '\r' as u8;
static TAB: u8 = '\t' as u8;
static STAR: u8 = '*' as u8;
static DASH: u8 = '-' as u8;
static UNDERSCORE: u8 = '_' as u8;
static TILDE: u8 = '~' as u8;
static BACKTICK: u8 = '`' as u8;

//
// Skip up to three leading spaces.
//
// Up to three leading spaces are allowed for many elements.
//
// We don't need to care about a TAB here as in this position it is equivalent
// to 4 spaces, which means that when we find a TAB here we would not parse the
// corresponding element.
//
fn skip_initial_three_spaces<'a>(buf: &'a[u8])-> &'a[u8] {
    let mut buf = buf;
    if buf.head() == Some(&SP) { buf = buf.tail();
    if buf.head() == Some(&SP) { buf = buf.tail();
    if buf.head() == Some(&SP) { buf = buf.tail(); } } }
    return buf;
}

//
// Return Some(`rem`) if the line is a horizontal rule, with `rem` being the
// buf after the hrule. Otherwise return None.
//
fn is_hrule<'a>(buf: &'a[u8]) -> Option<&'a[u8]> {
    let buf = skip_initial_three_spaces(buf);

    let item = match buf.head() {
        Some(&c) if c == STAR ||
                    c == DASH ||
                    c == UNDERSCORE => c,
        _                           => return None
    };

    // The count of '*', '-' or '_'
    let mut cnt: uint = 0;

    // Counts the consumed spaces (and the final NL)
    let mut spc: uint = 0;

    for &ch in buf.iter() {
        if      ch == item { cnt += 1; }
        else if ch == NL   { spc += 1; break; }
        else if ch == SP   { spc += 1; }
        else               { return None; }
    }

    if cnt >= 3 {
        Some(buf.slice_from(cnt + spc))
    } else {
        None
    }
}

#[test]
fn test_is_hrule() {
    // examples as given on the markdown homepage
    assert!(is_hrule(bytes!("* * *\n")).is_some());
    assert!(is_hrule(bytes!("***\n")).is_some());
    assert!(is_hrule(bytes!("*****\n")).is_some());
    assert!(is_hrule(bytes!("- - -\n")).is_some());
    assert!(is_hrule(bytes!("---------------------------------------\n")).is_some());

    // up to three spaces ignored
    assert!(is_hrule(bytes!(" ***\n")).is_some());
    assert!(is_hrule(bytes!("  ***\n")).is_some());
    assert!(is_hrule(bytes!("   ***\n")).is_some());

    // but not four, or a tab which is equivalent to four spaces
    assert!(is_hrule(bytes!("    ***\n")).is_none());
    assert!(is_hrule(bytes!("\t***\n")).is_none());

    // need at least three
    assert!(is_hrule(bytes!("*\n")).is_none());
    assert!(is_hrule(bytes!("**\n")).is_none());
    assert!(is_hrule(bytes!("* *\n")).is_none());
    assert!(is_hrule(bytes!("   * *\n")).is_none());

    // Also works without newline at the end
    assert!(is_hrule(bytes!("* * *")).is_some());

    // And underscores also supported
    assert!(is_hrule(bytes!("___")).is_some());
    assert!(is_hrule(bytes!("______________")).is_some());
    assert!(is_hrule(bytes!(" ______________")).is_some());

    // Test if the remaining buf actually works.
    let s = bytes!("   * * *\nremaining");
    let res = is_hrule(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), bytes!("remaining"));
}

//
// Return Some(`rem`) if the line is an empty line, with `rem` being the buf
// after the empty line. Otherwise return None.
//
fn is_empty<'a>(buf: &'a[u8]) -> Option<&'a[u8]> {
    let mut cnt: uint = 0;

    for &ch in buf.iter() {
        if      ch == NL  { cnt += 1; break; }
        else if ch == CR  { cnt += 1; }
        else if ch == SP  { cnt += 1; }
        else if ch == TAB { cnt += 1; }
        else              { return None; }
    }

    if cnt > 0 {
        Some(buf.slice_from(cnt))
    } else {
        None
    }
}

#[test]
fn test_is_empty() {
    assert!(is_empty(bytes!("\n")).is_some());
    assert!(is_empty(bytes!("    \n")).is_some());
    assert!(is_empty(bytes!("  \t  \n")).is_some());
    assert!(is_empty(bytes!("  \t  \r\n")).is_some());
    assert!(is_empty(bytes!("  \t  \nabc")).is_some());
    assert!(is_empty(bytes!("  \t  ")).is_some());

    assert!(is_empty(bytes!("a")).is_none());
    assert!(is_empty(bytes!(" a")).is_none());
    assert!(is_empty(bytes!(" a\n")).is_none());
    assert!(is_empty(bytes!(" \ta\n")).is_none());

    // Test if the remaining buf actually works.
    let s = bytes!("   \t\r\nremaining");
    let res = is_empty(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), bytes!("remaining"));
}

fn is_codefence<'a>(buf: &'a[u8]) -> Option<(&'a[u8], uint, u8)> {
    let buf = skip_initial_three_spaces(buf);

    let item = match buf.head() {
        Some(&c) if c == TILDE ||
                    c == BACKTICK => c,
        _                         => return None
    };

    // The count of '~' or '`' characters
    let mut cnt: uint = 0;

    for &ch in buf.iter() {
        if ch == item { cnt += 1; }
        else          { break; }
    }

    if cnt >= 3 {
        Some((buf.slice_from(cnt), cnt, item))
    } else {
        None
    }
}

#[test]
fn test_is_codefence() {
    assert!(is_codefence(bytes!("```")).is_some());
    assert!(is_codefence(bytes!("~~~")).is_some());
    assert!(is_codefence(bytes!("`````````")).is_some());
    assert!(is_codefence(bytes!("~~~~")).is_some());
    assert!(is_codefence(bytes!("   ```")).is_some());
    assert!(is_codefence(bytes!("  ~~~")).is_some());

    assert!(is_codefence(bytes!("  ~~")).is_none());
    assert!(is_codefence(bytes!(" ``")).is_none());
    assert!(is_codefence(bytes!("    ```")).is_none());
    assert!(is_codefence(bytes!("\t```")).is_none());

    // Test if the remaining buf actually works.
    let s = bytes!("   ```remaining\n");
    let res = is_codefence(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), (bytes!("remaining\n"), 3, BACKTICK));

    let s = bytes!("   ~~~~~~~~remaining\n");
    let res = is_codefence(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), (bytes!("remaining\n"), 8, TILDE));
}

<commit_msg>Replace depreciated bytes! macro with byte literals<commit_after>// This code is heavily inspired by hoedown.

//
// Performance observations:
//
// Note that buf.head() == Some(&ch) is much faster than buf[0] == ch.
//

static SP: u8 = ' ' as u8;
static NL: u8 = '\n' as u8;
static CR: u8 = '\r' as u8;
static TAB: u8 = '\t' as u8;
static STAR: u8 = '*' as u8;
static DASH: u8 = '-' as u8;
static UNDERSCORE: u8 = '_' as u8;
static TILDE: u8 = '~' as u8;
static BACKTICK: u8 = '`' as u8;

//
// Skip up to three leading spaces.
//
// Up to three leading spaces are allowed for many elements.
//
// We don't need to care about a TAB here as in this position it is equivalent
// to 4 spaces, which means that when we find a TAB here we would not parse the
// corresponding element.
//
fn skip_initial_three_spaces<'a>(buf: &'a[u8])-> &'a[u8] {
    let mut buf = buf;
    if buf.head() == Some(&SP) { buf = buf.tail();
    if buf.head() == Some(&SP) { buf = buf.tail();
    if buf.head() == Some(&SP) { buf = buf.tail(); } } }
    return buf;
}

//
// Return Some(`rem`) if the line is a horizontal rule, with `rem` being the
// buf after the hrule. Otherwise return None.
//
fn is_hrule<'a>(buf: &'a[u8]) -> Option<&'a[u8]> {
    let buf = skip_initial_three_spaces(buf);

    let item = match buf.head() {
        Some(&c) if c == STAR ||
                    c == DASH ||
                    c == UNDERSCORE => c,
        _                           => return None
    };

    // The count of '*', '-' or '_'
    let mut cnt: uint = 0;

    // Counts the consumed spaces (and the final NL)
    let mut spc: uint = 0;

    for &ch in buf.iter() {
        if      ch == item { cnt += 1; }
        else if ch == NL   { spc += 1; break; }
        else if ch == SP   { spc += 1; }
        else               { return None; }
    }

    if cnt >= 3 {
        Some(buf.slice_from(cnt + spc))
    } else {
        None
    }
}

#[test]
fn test_is_hrule() {
    // examples as given on the markdown homepage
    assert!(is_hrule(b"* * *\n").is_some());
    assert!(is_hrule(b"***\n").is_some());
    assert!(is_hrule(b"*****\n").is_some());
    assert!(is_hrule(b"- - -\n").is_some());
    assert!(is_hrule(b"---------------------------------------\n").is_some());

    // up to three spaces ignored
    assert!(is_hrule(b" ***\n").is_some());
    assert!(is_hrule(b"  ***\n").is_some());
    assert!(is_hrule(b"   ***\n").is_some());

    // but not four, or a tab which is equivalent to four spaces
    assert!(is_hrule(b"    ***\n").is_none());
    assert!(is_hrule(b"\t***\n").is_none());

    // need at least three
    assert!(is_hrule(b"*\n").is_none());
    assert!(is_hrule(b"**\n").is_none());
    assert!(is_hrule(b"* *\n").is_none());
    assert!(is_hrule(b"   * *\n").is_none());

    // Also works without newline at the end
    assert!(is_hrule(b"* * *").is_some());

    // And underscores also supported
    assert!(is_hrule(b"___").is_some());
    assert!(is_hrule(b"______________").is_some());
    assert!(is_hrule(b" ______________").is_some());

    // Test if the remaining buf actually works.
    let s = b"   * * *\nremaining";
    let res = is_hrule(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), b"remaining");
}

//
// Return Some(`rem`) if the line is an empty line, with `rem` being the buf
// after the empty line. Otherwise return None.
//
fn is_empty<'a>(buf: &'a[u8]) -> Option<&'a[u8]> {
    let mut cnt: uint = 0;

    for &ch in buf.iter() {
        if      ch == NL  { cnt += 1; break; }
        else if ch == CR  { cnt += 1; }
        else if ch == SP  { cnt += 1; }
        else if ch == TAB { cnt += 1; }
        else              { return None; }
    }

    if cnt > 0 {
        Some(buf.slice_from(cnt))
    } else {
        None
    }
}

#[test]
fn test_is_empty() {
    assert!(is_empty(b"\n").is_some());
    assert!(is_empty(b"    \n").is_some());
    assert!(is_empty(b"  \t  \n").is_some());
    assert!(is_empty(b"  \t  \r\n").is_some());
    assert!(is_empty(b"  \t  \nabc").is_some());
    assert!(is_empty(b"  \t  ").is_some());

    assert!(is_empty(b"a").is_none());
    assert!(is_empty(b" a").is_none());
    assert!(is_empty(b" a\n").is_none());
    assert!(is_empty(b" \ta\n").is_none());

    // Test if the remaining buf actually works.
    let s = b"   \t\r\nremaining";
    let res = is_empty(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), b"remaining");
}

fn is_codefence<'a>(buf: &'a[u8]) -> Option<(&'a[u8], uint, u8)> {
    let buf = skip_initial_three_spaces(buf);

    let item = match buf.head() {
        Some(&c) if c == TILDE ||
                    c == BACKTICK => c,
        _                         => return None
    };

    // The count of '~' or '`' characters
    let mut cnt: uint = 0;

    for &ch in buf.iter() {
        if ch == item { cnt += 1; }
        else          { break; }
    }

    if cnt >= 3 {
        Some((buf.slice_from(cnt), cnt, item))
    } else {
        None
    }
}

#[test]
fn test_is_codefence() {
    assert!(is_codefence(b"```").is_some());
    assert!(is_codefence(b"~~~").is_some());
    assert!(is_codefence(b"`````````").is_some());
    assert!(is_codefence(b"~~~~").is_some());
    assert!(is_codefence(b"   ```").is_some());
    assert!(is_codefence(b"  ~~~").is_some());

    assert!(is_codefence(b"  ~~").is_none());
    assert!(is_codefence(b" ``").is_none());
    assert!(is_codefence(b"    ```").is_none());
    assert!(is_codefence(b"\t```").is_none());

    // Test if the remaining buf actually works.
    let s = b"   ```remaining\n";
    let res = is_codefence(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), (b"remaining\n", 3, BACKTICK));

    let s = b"   ~~~~~~~~remaining\n";
    let res = is_codefence(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), (b"remaining\n", 8, TILDE));
}

<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::MouseEventBinding;
use dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
use dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods;
use dom::bindings::codegen::InheritTypes::{EventCast, UIEventCast, MouseEventDerived};
use dom::bindings::error::Error::NotSupported;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
use dom::bindings::utils::reflect_dom_object;
use dom::event::{Event, EventTypeId, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
use dom::uievent::UIEvent;
use dom::window::Window;
use util::opts;
use util::str::DOMString;
use std::cell::Cell;
use std::default::Default;

#[dom_struct]
pub struct MouseEvent {
    uievent: UIEvent,
    screen_x: Cell<i32>,
    screen_y: Cell<i32>,
    client_x: Cell<i32>,
    client_y: Cell<i32>,
    ctrl_key: Cell<bool>,
    shift_key: Cell<bool>,
    alt_key: Cell<bool>,
    meta_key: Cell<bool>,
    button: Cell<i16>,
    related_target: MutNullableHeap<JS<EventTarget>>,
}

impl MouseEventDerived for Event {
    fn is_mouseevent(&self) -> bool {
        *self.type_id() == EventTypeId::MouseEvent
    }
}

impl MouseEvent {
    fn new_inherited() -> MouseEvent {
        MouseEvent {
            uievent: UIEvent::new_inherited(EventTypeId::MouseEvent),
            screen_x: Cell::new(0),
            screen_y: Cell::new(0),
            client_x: Cell::new(0),
            client_y: Cell::new(0),
            ctrl_key: Cell::new(false),
            shift_key: Cell::new(false),
            alt_key: Cell::new(false),
            meta_key: Cell::new(false),
            button: Cell::new(0),
            related_target: Default::default(),
        }
    }

    pub fn new_uninitialized(window: &Window) -> Root<MouseEvent> {
        reflect_dom_object(box MouseEvent::new_inherited(),
                           GlobalRef::Window(window),
                           MouseEventBinding::Wrap)
    }

    pub fn new(window: &Window,
               type_: DOMString,
               canBubble: EventBubbles,
               cancelable: EventCancelable,
               view: Option<&Window>,
               detail: i32,
               screenX: i32,
               screenY: i32,
               clientX: i32,
               clientY: i32,
               ctrlKey: bool,
               altKey: bool,
               shiftKey: bool,
               metaKey: bool,
               button: i16,
               relatedTarget: Option<&EventTarget>) -> Root<MouseEvent> {
        let ev = MouseEvent::new_uninitialized(window);
        ev.r().InitMouseEvent(type_, canBubble == EventBubbles::Bubbles, cancelable == EventCancelable::Cancelable,
                              view, detail,
                              screenX, screenY, clientX, clientY,
                              ctrlKey, altKey, shiftKey, metaKey,
                              button, relatedTarget);
        ev
    }

    pub fn Constructor(global: GlobalRef,
                       type_: DOMString,
                       init: &MouseEventBinding::MouseEventInit) -> Fallible<Root<MouseEvent>> {
        let bubbles = if init.parent.parent.parent.bubbles {
            EventBubbles::Bubbles
        } else {
            EventBubbles::DoesNotBubble
        };
        let cancelable = if init.parent.parent.parent.cancelable {
            EventCancelable::Cancelable
        } else {
        EventCancelable::NotCancelable
        };
        let event = MouseEvent::new(global.as_window(), type_,
                                    bubbles,
                                    cancelable,
                                    init.parent.parent.view.r(),
                                    init.parent.parent.detail,
                                    init.screenX, init.screenY,
                                    init.clientX, init.clientY, init.parent.ctrlKey,
                                    init.parent.altKey, init.parent.shiftKey, init.parent.metaKey,
                                    init.button, init.relatedTarget.r());
        Ok(event)
    }
}

impl<'a> MouseEventMethods for &'a MouseEvent {
    // https://w3c.github.io/uievents/#widl-MouseEvent-screenX
    fn ScreenX(self) -> i32 {
        self.screen_x.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-screenY
    fn ScreenY(self) -> i32 {
        self.screen_y.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-clientX
    fn ClientX(self) -> i32 {
        self.client_x.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-clientY
    fn ClientY(self) -> i32 {
        self.client_y.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-ctrlKey
    fn CtrlKey(self) -> bool {
        self.ctrl_key.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-shiftKey
    fn ShiftKey(self) -> bool {
        self.shift_key.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-altKey
    fn AltKey(self) -> bool {
        self.alt_key.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-metaKey
    fn MetaKey(self) -> bool {
        self.meta_key.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-button
    fn Button(self) -> i16 {
        self.button.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-relatedTarget
    fn GetRelatedTarget(self) -> Option<Root<EventTarget>> {
        self.related_target.get().map(Root::from_rooted)
    }

    // See discussion at:
    //  - https://github.com/servo/servo/issues/6643
    //  - https://bugzilla.mozilla.org/show_bug.cgi?id=1186125
    // This returns the same result as current gecko.
    // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which
    fn Which(self) -> i32 {
        if opts::experimental_enabled() {
            (self.button.get() + 1) as i32
        } else {
            0
        }
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-initMouseEvent
    fn InitMouseEvent(self,
                      typeArg: DOMString,
                      canBubbleArg: bool,
                      cancelableArg: bool,
                      viewArg: Option<&Window>,
                      detailArg: i32,
                      screenXArg: i32,
                      screenYArg: i32,
                      clientXArg: i32,
                      clientYArg: i32,
                      ctrlKeyArg: bool,
                      altKeyArg: bool,
                      shiftKeyArg: bool,
                      metaKeyArg: bool,
                      buttonArg: i16,
                      relatedTargetArg: Option<&EventTarget>) {
        let event: &Event = EventCast::from_ref(self);
        if event.dispatching() {
            return;
        }

        let uievent: &UIEvent = UIEventCast::from_ref(self);
        uievent.InitUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg);
        self.screen_x.set(screenXArg);
        self.screen_y.set(screenYArg);
        self.client_x.set(clientXArg);
        self.client_y.set(clientYArg);
        self.ctrl_key.set(ctrlKeyArg);
        self.alt_key.set(altKeyArg);
        self.shift_key.set(shiftKeyArg);
        self.meta_key.set(metaKeyArg);
        self.button.set(buttonArg);
        self.related_target.set(relatedTargetArg.map(JS::from_ref));
    }
}

<commit_msg>Auto merge of #6810 - Ms2ger:warnings, r=metajack<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::MouseEventBinding;
use dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
use dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods;
use dom::bindings::codegen::InheritTypes::{EventCast, UIEventCast, MouseEventDerived};
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
use dom::bindings::utils::reflect_dom_object;
use dom::event::{Event, EventTypeId, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
use dom::uievent::UIEvent;
use dom::window::Window;
use util::opts;
use util::str::DOMString;
use std::cell::Cell;
use std::default::Default;

#[dom_struct]
pub struct MouseEvent {
    uievent: UIEvent,
    screen_x: Cell<i32>,
    screen_y: Cell<i32>,
    client_x: Cell<i32>,
    client_y: Cell<i32>,
    ctrl_key: Cell<bool>,
    shift_key: Cell<bool>,
    alt_key: Cell<bool>,
    meta_key: Cell<bool>,
    button: Cell<i16>,
    related_target: MutNullableHeap<JS<EventTarget>>,
}

impl MouseEventDerived for Event {
    fn is_mouseevent(&self) -> bool {
        *self.type_id() == EventTypeId::MouseEvent
    }
}

impl MouseEvent {
    fn new_inherited() -> MouseEvent {
        MouseEvent {
            uievent: UIEvent::new_inherited(EventTypeId::MouseEvent),
            screen_x: Cell::new(0),
            screen_y: Cell::new(0),
            client_x: Cell::new(0),
            client_y: Cell::new(0),
            ctrl_key: Cell::new(false),
            shift_key: Cell::new(false),
            alt_key: Cell::new(false),
            meta_key: Cell::new(false),
            button: Cell::new(0),
            related_target: Default::default(),
        }
    }

    pub fn new_uninitialized(window: &Window) -> Root<MouseEvent> {
        reflect_dom_object(box MouseEvent::new_inherited(),
                           GlobalRef::Window(window),
                           MouseEventBinding::Wrap)
    }

    pub fn new(window: &Window,
               type_: DOMString,
               canBubble: EventBubbles,
               cancelable: EventCancelable,
               view: Option<&Window>,
               detail: i32,
               screenX: i32,
               screenY: i32,
               clientX: i32,
               clientY: i32,
               ctrlKey: bool,
               altKey: bool,
               shiftKey: bool,
               metaKey: bool,
               button: i16,
               relatedTarget: Option<&EventTarget>) -> Root<MouseEvent> {
        let ev = MouseEvent::new_uninitialized(window);
        ev.r().InitMouseEvent(type_, canBubble == EventBubbles::Bubbles, cancelable == EventCancelable::Cancelable,
                              view, detail,
                              screenX, screenY, clientX, clientY,
                              ctrlKey, altKey, shiftKey, metaKey,
                              button, relatedTarget);
        ev
    }

    pub fn Constructor(global: GlobalRef,
                       type_: DOMString,
                       init: &MouseEventBinding::MouseEventInit) -> Fallible<Root<MouseEvent>> {
        let bubbles = if init.parent.parent.parent.bubbles {
            EventBubbles::Bubbles
        } else {
            EventBubbles::DoesNotBubble
        };
        let cancelable = if init.parent.parent.parent.cancelable {
            EventCancelable::Cancelable
        } else {
        EventCancelable::NotCancelable
        };
        let event = MouseEvent::new(global.as_window(), type_,
                                    bubbles,
                                    cancelable,
                                    init.parent.parent.view.r(),
                                    init.parent.parent.detail,
                                    init.screenX, init.screenY,
                                    init.clientX, init.clientY, init.parent.ctrlKey,
                                    init.parent.altKey, init.parent.shiftKey, init.parent.metaKey,
                                    init.button, init.relatedTarget.r());
        Ok(event)
    }
}

impl<'a> MouseEventMethods for &'a MouseEvent {
    // https://w3c.github.io/uievents/#widl-MouseEvent-screenX
    fn ScreenX(self) -> i32 {
        self.screen_x.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-screenY
    fn ScreenY(self) -> i32 {
        self.screen_y.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-clientX
    fn ClientX(self) -> i32 {
        self.client_x.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-clientY
    fn ClientY(self) -> i32 {
        self.client_y.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-ctrlKey
    fn CtrlKey(self) -> bool {
        self.ctrl_key.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-shiftKey
    fn ShiftKey(self) -> bool {
        self.shift_key.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-altKey
    fn AltKey(self) -> bool {
        self.alt_key.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-metaKey
    fn MetaKey(self) -> bool {
        self.meta_key.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-button
    fn Button(self) -> i16 {
        self.button.get()
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-relatedTarget
    fn GetRelatedTarget(self) -> Option<Root<EventTarget>> {
        self.related_target.get().map(Root::from_rooted)
    }

    // See discussion at:
    //  - https://github.com/servo/servo/issues/6643
    //  - https://bugzilla.mozilla.org/show_bug.cgi?id=1186125
    // This returns the same result as current gecko.
    // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which
    fn Which(self) -> i32 {
        if opts::experimental_enabled() {
            (self.button.get() + 1) as i32
        } else {
            0
        }
    }

    // https://w3c.github.io/uievents/#widl-MouseEvent-initMouseEvent
    fn InitMouseEvent(self,
                      typeArg: DOMString,
                      canBubbleArg: bool,
                      cancelableArg: bool,
                      viewArg: Option<&Window>,
                      detailArg: i32,
                      screenXArg: i32,
                      screenYArg: i32,
                      clientXArg: i32,
                      clientYArg: i32,
                      ctrlKeyArg: bool,
                      altKeyArg: bool,
                      shiftKeyArg: bool,
                      metaKeyArg: bool,
                      buttonArg: i16,
                      relatedTargetArg: Option<&EventTarget>) {
        let event: &Event = EventCast::from_ref(self);
        if event.dispatching() {
            return;
        }

        let uievent: &UIEvent = UIEventCast::from_ref(self);
        uievent.InitUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg);
        self.screen_x.set(screenXArg);
        self.screen_y.set(screenYArg);
        self.client_x.set(clientXArg);
        self.client_y.set(clientYArg);
        self.ctrl_key.set(ctrlKeyArg);
        self.alt_key.set(altKeyArg);
        self.shift_key.set(shiftKeyArg);
        self.meta_key.set(metaKeyArg);
        self.button.set(buttonArg);
        self.related_target.set(relatedTargetArg.map(JS::from_ref));
    }
}

<|endoftext|>


<commit_before>// https://leetcode.com/problems/minimum-number-of-increments-on-subarrays-to-form-a-target-array/
pub fn min_number_operations(target: Vec<i32>) -> i32 {
    todo!()
}

fn main() {
    println!("{}", min_number_operations(vec![1, 2, 3, 2, 1])); // 3
    println!("{}", min_number_operations(vec![3, 1, 1, 2])); // 4
    println!("{}", min_number_operations(vec![3, 1, 5, 4, 2])); // 7
}
<commit_msg>Solve problem 1526<commit_after>// https://leetcode.com/problems/minimum-number-of-increments-on-subarrays-to-form-a-target-array/
pub fn min_number_operations(target: Vec<i32>) -> i32 {
    let mut answer = 0;
    let mut previous = 0;
    for current in target {
        if current - previous > 0 {
            answer += current - previous;
        }
        previous = current;
    }
    answer
}

fn main() {
    println!("{}", min_number_operations(vec![1, 2, 3, 2, 1])); // 3
    println!("{}", min_number_operations(vec![3, 1, 1, 2])); // 4
    println!("{}", min_number_operations(vec![3, 1, 5, 4, 2])); // 7
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/make-array-zero-by-subtracting-equal-amounts/
pub fn minimum_operations(nums: Vec<i32>) -> i32 {
    todo!()
}

fn main() {
    println!("{}", minimum_operations(vec![1, 5, 0, 3, 5])); // 3
    println!("{}", minimum_operations(vec![0])); //
    println!("{}", minimum_operations(vec![1, 5, 0, 3, 5, 2])); // 4
}
<commit_msg>Solve problem 2357<commit_after>use std::collections::HashSet;

// https://leetcode.com/problems/make-array-zero-by-subtracting-equal-amounts/
pub fn minimum_operations(nums: Vec<i32>) -> i32 {
    let mut set: HashSet<i32> = HashSet::new();
    for num in nums.iter() {
        if *num != 0 {
            set.insert(*num);
        }
    }
    set.len() as i32
}

fn main() {
    println!("{}", minimum_operations(vec![1, 5, 0, 3, 5])); // 3
    println!("{}", minimum_operations(vec![0])); //
    println!("{}", minimum_operations(vec![1, 5, 0, 3, 5, 2])); // 4
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::rc::Rc;

// https://leetcode.com/problems/reverse-odd-levels-of-binary-tree/
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        TreeNode {
            val,
            left: None,
            right: None,
        }
    }
}

pub fn reverse_odd_levels(root: Option<Rc<RefCell<TreeNode>>>) -> Option<Rc<RefCell<TreeNode>>> {
    todo!()
}

fn main() {}
<commit_msg>Update problem 2415<commit_after>use std::cell::RefCell;
use std::rc::Rc;

// https://leetcode.com/problems/reverse-odd-levels-of-binary-tree/
#[derive(Debug, PartialEq, Eq)]
pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    #[inline]
    pub fn new(val: i32) -> Self {
        TreeNode {
            val,
            left: None,
            right: None,
        }
    }
}

pub fn reverse_odd_levels(root: Option<Rc<RefCell<TreeNode>>>) -> Option<Rc<RefCell<TreeNode>>> {
    todo!()
}

fn main() {
    fn create_node(value: i32) -> Option<Rc<RefCell<TreeNode>>> {
        Some(Rc::new(RefCell::new(TreeNode::new(value))))
    }

    fn add_left(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().left = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().left.clone()
    }

    fn add_right(
        parent: &Option<Rc<RefCell<TreeNode>>>,
        value: i32,
    ) -> Option<Rc<RefCell<TreeNode>>> {
        parent.as_ref().unwrap().as_ref().borrow_mut().right = create_node(value);
        parent.as_ref().unwrap().as_ref().borrow().right.clone()
    }

    let root = create_node(2);
    let left = add_left(&root, 3);
    add_left(&left, 8);
    add_right(&left, 13);
    let right = add_right(&root, 5);
    add_left(&right, 21);
    add_right(&right, 34);
    println!("{:?}", reverse_odd_levels(root)); // [2,5,3,8,13,21,34]

    let root = create_node(7);
    add_left(&root, 13);
    add_right(&root, 11);
    println!("{:?}", reverse_odd_levels(root)); // [7,11,13]
}
<|endoftext|>


<commit_before>/// Worker contains all workers that do the expensive job in background.

use std::sync::Arc;
use std::thread::{self, JoinHandle, Builder};
use std::io;
use std::fmt::Display;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{self, Sender, Receiver};
use std::result;

use util::SlowTimer;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Stopped
        Io(e: io::Error) {
            from()
            display("{}", e)
        }
    }
}

impl<T> From<mpsc::SendError<T>> for Error {
    fn from(_: mpsc::SendError<T>) -> Error {
        // do we need to return the failed data
        Error::Stopped
    }
}

pub type Result<T> = result::Result<T, Error>;

pub trait Runnable<T: Display> {
    fn run(&mut self, t: T);
}

pub trait BatchRunnable<T: Display> {
    /// run a batch of tasks.
    ///
    /// Please note that ts will be clear after invoking this method.
    fn run_batch(&mut self, ts: &mut Vec<T>);
}

impl<T: Display, R: Runnable<T>> BatchRunnable<T> for R {
    fn run_batch(&mut self, ts: &mut Vec<T>) {
        for t in ts.drain(..) {
            let task_str = format!("{}", t);
            let timer = SlowTimer::new();
            self.run(t);
            slow_log!(timer, "handle task {}", task_str);
        }
    }
}

/// Scheduler provides interface to schedule task to underlying workers.
pub struct Scheduler<T> {
    counter: Arc<AtomicUsize>,
    sender: Sender<Option<T>>,
}

impl<T: Display> Scheduler<T> {
    fn new(counter: AtomicUsize, sender: Sender<Option<T>>) -> Scheduler<T> {
        Scheduler {
            counter: Arc::new(counter),
            sender: sender,
        }
    }

    /// Schedule a task to run.
    ///
    /// If the worker is stopped, an error will return.
    pub fn schedule(&self, task: T) -> Result<()> {
        debug!("scheduling task {}", task);
        try!(self.sender.send(Some(task)));
        self.counter.fetch_add(1, Ordering::SeqCst);
        Ok(())
    }

    /// Check if underlying worker can't handle task immediately.
    pub fn is_busy(&self) -> bool {
        self.counter.load(Ordering::SeqCst) > 0
    }
}

impl<T: Display> Clone for Scheduler<T> {
    fn clone(&self) -> Scheduler<T> {
        Scheduler {
            counter: self.counter.clone(),
            sender: self.sender.clone(),
        }
    }
}

/// Create a scheduler that can't be scheduled any task.
///
/// Useful for test purpose.
#[cfg(test)]
pub fn dummy_scheduler<T: Display>() -> Scheduler<T> {
    let (tx, _) = mpsc::channel();
    Scheduler::new(AtomicUsize::new(0), tx)
}

/// A worker that can schedule time consuming tasks.
pub struct Worker<T: Display> {
    name: String,
    scheduler: Scheduler<T>,
    receiver: Option<Receiver<Option<T>>>,
    handle: Option<JoinHandle<()>>,
}

fn poll<R, T>(mut runner: R, rx: Receiver<Option<T>>, counter: Arc<AtomicUsize>, batch_size: usize)
    where R: BatchRunnable<T> + Send + 'static,
          T: Display + Send + 'static
{
    let mut keep_going = true;
    let mut buffer = Vec::with_capacity(batch_size);
    while keep_going {
        let t = rx.recv();
        match t {
            Ok(Some(t)) => buffer.push(t),
            _ => return,
        }
        while buffer.len() < batch_size {
            match rx.try_recv() {
                Ok(None) => {
                    keep_going = false;
                    break;
                }
                Ok(Some(t)) => buffer.push(t),
                _ => break,
            }
        }
        counter.fetch_sub(buffer.len(), Ordering::SeqCst);
        runner.run_batch(&mut buffer);
        buffer.clear();
    }
}

impl<T: Display + Send + 'static> Worker<T> {
    /// Create a worker.
    pub fn new<S: Into<String>>(name: S) -> Worker<T> {
        let (tx, rx) = mpsc::channel();
        Worker {
            name: name.into(),
            scheduler: Scheduler::new(AtomicUsize::new(0), tx),
            receiver: Some(rx),
            handle: None,
        }
    }

    /// Start the worker.
    pub fn start<R: Runnable<T> + Send + 'static>(&mut self, runner: R) -> Result<()> {
        self.start_batch(runner, 1)
    }

    pub fn start_batch<R>(&mut self, runner: R, batch_size: usize) -> Result<()>
        where R: BatchRunnable<T> + Send + 'static
    {
        info!("starting working thread: {}", self.name);
        if self.receiver.is_none() {
            warn!("worker {} has been started.", self.name);
            return Ok(());
        }

        let rx = self.receiver.take().unwrap();
        let counter = self.scheduler.counter.clone();
        let h = try!(Builder::new()
            .name(thd_name!(self.name.clone()))
            .spawn(move || poll(runner, rx, counter, batch_size)));
        self.handle = Some(h);
        Ok(())
    }

    /// Get a scheduler to schedule task.
    pub fn scheduler(&self) -> Scheduler<T> {
        self.scheduler.clone()
    }

    /// Schedule a task to run.
    ///
    /// If the worker is stopped, an error will return.
    pub fn schedule(&self, task: T) -> Result<()> {
        self.scheduler.schedule(task)
    }

    /// Check if underlying worker can't handle task immediately.
    pub fn is_busy(&self) -> bool {
        self.handle.is_none() || self.scheduler.is_busy()
    }

    pub fn name(&self) -> &str {
        self.name.as_str()
    }

    /// Stop the worker thread.
    pub fn stop(&mut self) -> Option<thread::JoinHandle<()>> {
        // close sender explicitly so the background thread will exit.
        info!("stoping {}", self.name);
        if self.handle.is_none() {
            return None;
        }
        if let Err(e) = self.scheduler.sender.send(None) {
            warn!("failed to stop worker thread: {:?}", e);
        }
        self.handle.take()
    }
}

#[cfg(test)]
mod test {
    use std::thread;
    use std::sync::Arc;
    use std::sync::atomic::*;
    use std::cmp;
    use std::time::Duration;

    use super::*;

    struct CountRunner {
        count: Arc<AtomicUsize>,
    }

    impl Runnable<u64> for CountRunner {
        fn run(&mut self, step: u64) {
            self.count.fetch_add(step as usize, Ordering::SeqCst);
            thread::sleep(Duration::from_millis(10));
        }
    }

    struct BatchRunner {
        count: Arc<AtomicUsize>,
    }

    impl BatchRunnable<u64> for BatchRunner {
        fn run_batch(&mut self, ms: &mut Vec<u64>) {
            let total = ms.iter().fold(0, |l, &r| l + r);
            self.count.fetch_add(total as usize, Ordering::SeqCst);
            let max_sleep = ms.iter().fold(0, |l, &r| cmp::max(l, r));
            thread::sleep(Duration::from_millis(max_sleep));
        }
    }

    #[test]
    fn test_worker() {
        let mut worker = Worker::new("test-worker");
        let count = Arc::new(AtomicUsize::new(0));
        worker.start(CountRunner { count: count.clone() }).unwrap();
        assert!(!worker.is_busy());
        worker.schedule(50).unwrap();
        worker.schedule(50).unwrap();
        worker.schedule(50).unwrap();
        assert!(worker.is_busy());
        for _ in 0..100 {
            if !worker.is_busy() {
                break;
            }
            thread::sleep(Duration::from_millis(10));
        }
        assert!(!worker.is_busy());
        worker.stop().unwrap().join().unwrap();
        assert_eq!(count.load(Ordering::SeqCst), 150);
        // now worker can't handle any task
        assert!(worker.is_busy());
    }

    #[test]
    fn test_threaded() {
        let mut worker = Worker::new("test-worker-threaded");
        let count = Arc::new(AtomicUsize::new(0));
        worker.start(CountRunner { count: count.clone() }).unwrap();
        let scheduler = worker.scheduler();
        thread::spawn(move || {
            scheduler.schedule(100).unwrap();
            scheduler.schedule(100).unwrap();
        });
        for _ in 1..1000 {
            if worker.is_busy() {
                break;
            }
            thread::sleep(Duration::from_millis(1));
        }
        worker.stop().unwrap().join().unwrap();
        assert_eq!(count.load(Ordering::SeqCst), 200);
    }

    #[test]
    fn test_batch() {
        let mut worker = Worker::new("test-worker-batch");
        let count = Arc::new(AtomicUsize::new(0));
        worker.start_batch(BatchRunner { count: count.clone() }, 10).unwrap();
        for _ in 0..20 {
            worker.schedule(50).unwrap();
        }
        worker.stop().unwrap().join().unwrap();
        assert_eq!(count.load(Ordering::SeqCst), 20 * 50);
    }
}
<commit_msg>util: return task when fail to schedule (#885)<commit_after>/// Worker contains all workers that do the expensive job in background.

use std::sync::Arc;
use std::thread::{self, JoinHandle, Builder};
use std::io;
use std::fmt::{self, Formatter, Display, Debug};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{self, Sender, Receiver, SendError};
use std::error::Error;

use util::SlowTimer;

pub struct Stopped<T>(pub T);

impl<T> Display for Stopped<T> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "channel has been closed")
    }
}

impl<T> Debug for Stopped<T> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "channel has been closed")
    }
}

impl<T> From<Stopped<T>> for Box<Error + Sync + Send + 'static> {
    fn from(_: Stopped<T>) -> Box<Error + Sync + Send + 'static> {
        box_err!("channel has been closed")
    }
}

pub trait Runnable<T: Display> {
    fn run(&mut self, t: T);
}

pub trait BatchRunnable<T: Display> {
    /// run a batch of tasks.
    ///
    /// Please note that ts will be clear after invoking this method.
    fn run_batch(&mut self, ts: &mut Vec<T>);
}

impl<T: Display, R: Runnable<T>> BatchRunnable<T> for R {
    fn run_batch(&mut self, ts: &mut Vec<T>) {
        for t in ts.drain(..) {
            let task_str = format!("{}", t);
            let timer = SlowTimer::new();
            self.run(t);
            slow_log!(timer, "handle task {}", task_str);
        }
    }
}

/// Scheduler provides interface to schedule task to underlying workers.
pub struct Scheduler<T> {
    counter: Arc<AtomicUsize>,
    sender: Sender<Option<T>>,
}

impl<T: Display> Scheduler<T> {
    fn new(counter: AtomicUsize, sender: Sender<Option<T>>) -> Scheduler<T> {
        Scheduler {
            counter: Arc::new(counter),
            sender: sender,
        }
    }

    /// Schedule a task to run.
    ///
    /// If the worker is stopped, an error will return.
    pub fn schedule(&self, task: T) -> Result<(), Stopped<T>> {
        debug!("scheduling task {}", task);
        if let Err(SendError(Some(t))) = self.sender.send(Some(task)) {
            return Err(Stopped(t));
        }
        self.counter.fetch_add(1, Ordering::SeqCst);
        Ok(())
    }

    /// Check if underlying worker can't handle task immediately.
    pub fn is_busy(&self) -> bool {
        self.counter.load(Ordering::SeqCst) > 0
    }
}

impl<T: Display> Clone for Scheduler<T> {
    fn clone(&self) -> Scheduler<T> {
        Scheduler {
            counter: self.counter.clone(),
            sender: self.sender.clone(),
        }
    }
}

/// Create a scheduler that can't be scheduled any task.
///
/// Useful for test purpose.
#[cfg(test)]
pub fn dummy_scheduler<T: Display>() -> Scheduler<T> {
    let (tx, _) = mpsc::channel();
    Scheduler::new(AtomicUsize::new(0), tx)
}

/// A worker that can schedule time consuming tasks.
pub struct Worker<T: Display> {
    name: String,
    scheduler: Scheduler<T>,
    receiver: Option<Receiver<Option<T>>>,
    handle: Option<JoinHandle<()>>,
}

fn poll<R, T>(mut runner: R, rx: Receiver<Option<T>>, counter: Arc<AtomicUsize>, batch_size: usize)
    where R: BatchRunnable<T> + Send + 'static,
          T: Display + Send + 'static
{
    let mut keep_going = true;
    let mut buffer = Vec::with_capacity(batch_size);
    while keep_going {
        let t = rx.recv();
        match t {
            Ok(Some(t)) => buffer.push(t),
            _ => return,
        }
        while buffer.len() < batch_size {
            match rx.try_recv() {
                Ok(None) => {
                    keep_going = false;
                    break;
                }
                Ok(Some(t)) => buffer.push(t),
                _ => break,
            }
        }
        counter.fetch_sub(buffer.len(), Ordering::SeqCst);
        runner.run_batch(&mut buffer);
        buffer.clear();
    }
}

impl<T: Display + Send + 'static> Worker<T> {
    /// Create a worker.
    pub fn new<S: Into<String>>(name: S) -> Worker<T> {
        let (tx, rx) = mpsc::channel();
        Worker {
            name: name.into(),
            scheduler: Scheduler::new(AtomicUsize::new(0), tx),
            receiver: Some(rx),
            handle: None,
        }
    }

    /// Start the worker.
    pub fn start<R: Runnable<T> + Send + 'static>(&mut self, runner: R) -> Result<(), io::Error> {
        self.start_batch(runner, 1)
    }

    pub fn start_batch<R>(&mut self, runner: R, batch_size: usize) -> Result<(), io::Error>
        where R: BatchRunnable<T> + Send + 'static
    {
        info!("starting working thread: {}", self.name);
        if self.receiver.is_none() {
            warn!("worker {} has been started.", self.name);
            return Ok(());
        }

        let rx = self.receiver.take().unwrap();
        let counter = self.scheduler.counter.clone();
        let h = try!(Builder::new()
            .name(thd_name!(self.name.clone()))
            .spawn(move || poll(runner, rx, counter, batch_size)));
        self.handle = Some(h);
        Ok(())
    }

    /// Get a scheduler to schedule task.
    pub fn scheduler(&self) -> Scheduler<T> {
        self.scheduler.clone()
    }

    /// Schedule a task to run.
    ///
    /// If the worker is stopped, an error will return.
    pub fn schedule(&self, task: T) -> Result<(), Stopped<T>> {
        self.scheduler.schedule(task)
    }

    /// Check if underlying worker can't handle task immediately.
    pub fn is_busy(&self) -> bool {
        self.handle.is_none() || self.scheduler.is_busy()
    }

    pub fn name(&self) -> &str {
        self.name.as_str()
    }

    /// Stop the worker thread.
    pub fn stop(&mut self) -> Option<thread::JoinHandle<()>> {
        // close sender explicitly so the background thread will exit.
        info!("stoping {}", self.name);
        if self.handle.is_none() {
            return None;
        }
        if let Err(e) = self.scheduler.sender.send(None) {
            warn!("failed to stop worker thread: {:?}", e);
        }
        self.handle.take()
    }
}

#[cfg(test)]
mod test {
    use std::thread;
    use std::sync::Arc;
    use std::sync::atomic::*;
    use std::cmp;
    use std::time::Duration;

    use super::*;

    struct CountRunner {
        count: Arc<AtomicUsize>,
    }

    impl Runnable<u64> for CountRunner {
        fn run(&mut self, step: u64) {
            self.count.fetch_add(step as usize, Ordering::SeqCst);
            thread::sleep(Duration::from_millis(10));
        }
    }

    struct BatchRunner {
        count: Arc<AtomicUsize>,
    }

    impl BatchRunnable<u64> for BatchRunner {
        fn run_batch(&mut self, ms: &mut Vec<u64>) {
            let total = ms.iter().fold(0, |l, &r| l + r);
            self.count.fetch_add(total as usize, Ordering::SeqCst);
            let max_sleep = ms.iter().fold(0, |l, &r| cmp::max(l, r));
            thread::sleep(Duration::from_millis(max_sleep));
        }
    }

    #[test]
    fn test_worker() {
        let mut worker = Worker::new("test-worker");
        let count = Arc::new(AtomicUsize::new(0));
        worker.start(CountRunner { count: count.clone() }).unwrap();
        assert!(!worker.is_busy());
        worker.schedule(50).unwrap();
        worker.schedule(50).unwrap();
        worker.schedule(50).unwrap();
        assert!(worker.is_busy());
        for _ in 0..100 {
            if !worker.is_busy() {
                break;
            }
            thread::sleep(Duration::from_millis(10));
        }
        assert!(!worker.is_busy());
        worker.stop().unwrap().join().unwrap();
        assert_eq!(count.load(Ordering::SeqCst), 150);
        // now worker can't handle any task
        assert!(worker.is_busy());
    }

    #[test]
    fn test_threaded() {
        let mut worker = Worker::new("test-worker-threaded");
        let count = Arc::new(AtomicUsize::new(0));
        worker.start(CountRunner { count: count.clone() }).unwrap();
        let scheduler = worker.scheduler();
        thread::spawn(move || {
            scheduler.schedule(100).unwrap();
            scheduler.schedule(100).unwrap();
        });
        for _ in 1..1000 {
            if worker.is_busy() {
                break;
            }
            thread::sleep(Duration::from_millis(1));
        }
        worker.stop().unwrap().join().unwrap();
        assert_eq!(count.load(Ordering::SeqCst), 200);
    }

    #[test]
    fn test_batch() {
        let mut worker = Worker::new("test-worker-batch");
        let count = Arc::new(AtomicUsize::new(0));
        worker.start_batch(BatchRunner { count: count.clone() }, 10).unwrap();
        for _ in 0..20 {
            worker.schedule(50).unwrap();
        }
        worker.stop().unwrap().join().unwrap();
        assert_eq!(count.load(Ordering::SeqCst), 20 * 50);
    }
}
<|endoftext|>