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

// Code that generates a test runner to run all the tests in a crate

use driver::session;
use front::config;

use std::cell::RefCell;
use std::vec;
use syntax::ast_util::*;
use syntax::attr::AttrMetaMethods;
use syntax::attr;
use syntax::codemap::{dummy_sp, Span, ExpnInfo, NameAndSpan, MacroAttribute};
use syntax::codemap;
use syntax::ext::base::ExtCtxt;
use syntax::fold::ast_fold;
use syntax::fold;
use syntax::opt_vec;
use syntax::print::pprust;
use syntax::{ast, ast_util};
use syntax::util::small_vector::SmallVector;

struct Test {
    span: Span,
    path: ~[ast::Ident],
    bench: bool,
    ignore: bool,
    should_fail: bool
}

struct TestCtxt {
    sess: session::Session,
    path: RefCell<~[ast::Ident]>,
    ext_cx: @ExtCtxt,
    testfns: ~[Test],
    is_extra: bool,
    config: ast::CrateConfig,
}

// Traverse the crate, collecting all the test functions, eliding any
// existing main functions, and synthesizing a main test harness
pub fn modify_for_testing(sess: session::Session,
                          crate: ast::Crate) -> ast::Crate {
    // We generate the test harness when building in the 'test'
    // configuration, either with the '--test' or '--cfg test'
    // command line options.
    let should_test = attr::contains_name(crate.config, "test");

    if should_test {
        generate_test_harness(sess, crate)
    } else {
        strip_test_functions(crate)
    }
}

struct TestHarnessGenerator {
    cx: @mut TestCtxt,
}

impl fold::ast_fold for TestHarnessGenerator {
    fn fold_crate(&self, c: ast::Crate) -> ast::Crate {
        let folded = fold::noop_fold_crate(c, self);

        // Add a special __test module to the crate that will contain code
        // generated for the test harness
        ast::Crate {
            module: add_test_module(self.cx, &folded.module),
            .. folded
        }
    }

    fn fold_item(&self, i: @ast::item) -> SmallVector<@ast::item> {
        {
            let mut path = self.cx.path.borrow_mut();
            path.get().push(i.ident);
        }
        debug!("current path: {}",
               ast_util::path_name_i(self.cx.path.get()));

        if is_test_fn(self.cx, i) || is_bench_fn(i) {
            match i.node {
                ast::item_fn(_, purity, _, _, _)
                    if purity == ast::unsafe_fn => {
                    let sess = self.cx.sess;
                    sess.span_fatal(i.span,
                                    "unsafe functions cannot be used for \
                                     tests");
                }
                _ => {
                    debug!("this is a test function");
                    let test = Test {
                        span: i.span,
                        path: self.cx.path.get(),
                        bench: is_bench_fn(i),
                        ignore: is_ignored(self.cx, i),
                        should_fail: should_fail(i)
                    };
                    self.cx.testfns.push(test);
                    // debug!("have {} test/bench functions",
                    //        cx.testfns.len());
                }
            }
        }

        let res = fold::noop_fold_item(i, self);
        {
            let mut path = self.cx.path.borrow_mut();
            path.get().pop();
        }
        res
    }

    fn fold_mod(&self, m: &ast::_mod) -> ast::_mod {
        // Remove any #[main] from the AST so it doesn't clash with
        // the one we're going to add. Only if compiling an executable.

        fn nomain(cx: @mut TestCtxt, item: @ast::item) -> @ast::item {
            if !*cx.sess.building_library {
                @ast::item {
                    attrs: item.attrs.iter().filter_map(|attr| {
                        if "main" != attr.name() {
                            Some(*attr)
                        } else {
                            None
                        }
                    }).collect(),
                    .. (*item).clone()
                }
            } else {
                item
            }
        }

        let mod_nomain = ast::_mod {
            view_items: m.view_items.clone(),
            items: m.items.iter().map(|i| nomain(self.cx, *i)).collect(),
        };

        fold::noop_fold_mod(&mod_nomain, self)
    }
}

fn generate_test_harness(sess: session::Session, crate: ast::Crate)
                         -> ast::Crate {
    let cx: @mut TestCtxt = @mut TestCtxt {
        sess: sess,
        ext_cx: ExtCtxt::new(sess.parse_sess, sess.opts.cfg.clone()),
        path: RefCell::new(~[]),
        testfns: ~[],
        is_extra: is_extra(&crate),
        config: crate.config.clone(),
    };

    let ext_cx = cx.ext_cx;
    ext_cx.bt_push(ExpnInfo {
        call_site: dummy_sp(),
        callee: NameAndSpan {
            name: @"test",
            format: MacroAttribute,
            span: None
        }
    });

    let fold = TestHarnessGenerator {
        cx: cx
    };
    let res = fold.fold_crate(crate);
    ext_cx.bt_pop();
    return res;
}

fn strip_test_functions(crate: ast::Crate) -> ast::Crate {
    // When not compiling with --test we should not compile the
    // #[test] functions
    config::strip_items(crate, |attrs| {
        !attr::contains_name(attrs, "test") &&
        !attr::contains_name(attrs, "bench")
    })
}

fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool {
    let has_test_attr = attr::contains_name(i.attrs, "test");

    fn has_test_signature(i: @ast::item) -> bool {
        match &i.node {
          &ast::item_fn(ref decl, _, _, ref generics, _) => {
            let no_output = match decl.output.node {
                ast::ty_nil => true,
                _ => false
            };
            decl.inputs.is_empty()
                && no_output
                && !generics.is_parameterized()
          }
          _ => false
        }
    }

    if has_test_attr && !has_test_signature(i) {
        let sess = cx.sess;
        sess.span_err(
            i.span,
            "functions used as tests must have signature fn() -> ()."
        );
    }

    return has_test_attr && has_test_signature(i);
}

fn is_bench_fn(i: @ast::item) -> bool {
    let has_bench_attr = attr::contains_name(i.attrs, "bench");

    fn has_test_signature(i: @ast::item) -> bool {
        match i.node {
            ast::item_fn(ref decl, _, _, ref generics, _) => {
                let input_cnt = decl.inputs.len();
                let no_output = match decl.output.node {
                    ast::ty_nil => true,
                    _ => false
                };
                let tparm_cnt = generics.ty_params.len();
                // NB: inadequate check, but we're running
                // well before resolve, can't get too deep.
                input_cnt == 1u
                    && no_output && tparm_cnt == 0u
            }
          _ => false
        }
    }

    return has_bench_attr && has_test_signature(i);
}

fn is_ignored(cx: @mut TestCtxt, i: @ast::item) -> bool {
    i.attrs.iter().any(|attr| {
        // check ignore(cfg(foo, bar))
        "ignore" == attr.name() && match attr.meta_item_list() {
            Some(ref cfgs) => attr::test_cfg(cx.config, cfgs.iter().map(|x| *x)),
            None => true
        }
    })
}

fn should_fail(i: @ast::item) -> bool {
    attr::contains_name(i.attrs, "should_fail")
}

fn add_test_module(cx: &TestCtxt, m: &ast::_mod) -> ast::_mod {
    let testmod = mk_test_module(cx);
    ast::_mod {
        items: vec::append_one(m.items.clone(), testmod),
        ..(*m).clone()
    }
}

/*

We're going to be building a module that looks more or less like:

mod __test {
  #[!resolve_unexported]
  extern mod extra (name = "extra", vers = "...");
  fn main() {
    #[main];
    extra::test::test_main_static(::os::args(), tests)
  }

  static tests : &'static [extra::test::TestDescAndFn] = &[
    ... the list of tests in the crate ...
  ];
}

*/

fn mk_std(cx: &TestCtxt) -> ast::view_item {
    let id_extra = cx.sess.ident_of("extra");
    let vi = if cx.is_extra {
        ast::view_item_use(
            ~[@nospan(ast::view_path_simple(id_extra,
                                            path_node(~[id_extra]),
                                            ast::DUMMY_NODE_ID))])
    } else {
        let mi = attr::mk_name_value_item_str(@"vers", @"0.9-pre");
        ast::view_item_extern_mod(id_extra, None, ~[mi], ast::DUMMY_NODE_ID)
    };
    ast::view_item {
        node: vi,
        attrs: ~[],
        vis: ast::public,
        span: dummy_sp()
    }
}

fn mk_test_module(cx: &TestCtxt) -> @ast::item {

    // Link to extra
    let view_items = ~[mk_std(cx)];

    // A constant vector of test descriptors.
    let tests = mk_tests(cx);

    // The synthesized main function which will call the console test runner
    // with our list of tests
    let mainfn = (quote_item!(cx.ext_cx,
        pub fn main() {
            #[main];
            extra::test::test_main_static(::std::os::args(), TESTS);
        }
    )).unwrap();

    let testmod = ast::_mod {
        view_items: view_items,
        items: ~[mainfn, tests],
    };
    let item_ = ast::item_mod(testmod);

    // This attribute tells resolve to let us call unexported functions
    let resolve_unexported_attr =
        attr::mk_attr(attr::mk_word_item(@"!resolve_unexported"));

    let item = ast::item {
        ident: cx.sess.ident_of("__test"),
        attrs: ~[resolve_unexported_attr],
        id: ast::DUMMY_NODE_ID,
        node: item_,
        vis: ast::public,
        span: dummy_sp(),
     };

    debug!("Synthetic test module:\n{}\n",
           pprust::item_to_str(&item, cx.sess.intr()));

    return @item;
}

fn nospan<T>(t: T) -> codemap::Spanned<T> {
    codemap::Spanned { node: t, span: dummy_sp() }
}

fn path_node(ids: ~[ast::Ident]) -> ast::Path {
    ast::Path {
        span: dummy_sp(),
        global: false,
        segments: ids.move_iter().map(|identifier| ast::PathSegment {
            identifier: identifier,
            lifetimes: opt_vec::Empty,
            types: opt_vec::Empty,
        }).collect()
    }
}

fn path_node_global(ids: ~[ast::Ident]) -> ast::Path {
    ast::Path {
        span: dummy_sp(),
        global: true,
        segments: ids.move_iter().map(|identifier| ast::PathSegment {
            identifier: identifier,
            lifetimes: opt_vec::Empty,
            types: opt_vec::Empty,
        }).collect()
    }
}

fn mk_tests(cx: &TestCtxt) -> @ast::item {
    // The vector of test_descs for this crate
    let test_descs = mk_test_descs(cx);

    (quote_item!(cx.ext_cx,
        pub static TESTS : &'static [self::extra::test::TestDescAndFn] =
            $test_descs
        ;
    )).unwrap()
}

fn is_extra(crate: &ast::Crate) -> bool {
    match attr::find_pkgid(crate.attrs) {
        Some(ref s) if "extra" == s.name => true,
        _ => false
    }
}

fn mk_test_descs(cx: &TestCtxt) -> @ast::Expr {
    debug!("building test vector from {} tests", cx.testfns.len());
    let mut descs = ~[];
    for test in cx.testfns.iter() {
        descs.push(mk_test_desc_and_fn_rec(cx, test));
    }

    let inner_expr = @ast::Expr {
        id: ast::DUMMY_NODE_ID,
        node: ast::ExprVec(descs, ast::MutImmutable),
        span: dummy_sp(),
    };

    @ast::Expr {
        id: ast::DUMMY_NODE_ID,
        node: ast::ExprVstore(inner_expr, ast::ExprVstoreSlice),
        span: dummy_sp(),
    }
}

fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::Expr {
    let span = test.span;
    let path = test.path.clone();

    debug!("encoding {}", ast_util::path_name_i(path));

    let name_lit: ast::lit =
        nospan(ast::lit_str(ast_util::path_name_i(path).to_managed(), ast::CookedStr));

    let name_expr = @ast::Expr {
          id: ast::DUMMY_NODE_ID,
          node: ast::ExprLit(@name_lit),
          span: span
    };

    let fn_path = path_node_global(path);

    let fn_expr = @ast::Expr {
        id: ast::DUMMY_NODE_ID,
        node: ast::ExprPath(fn_path),
        span: span,
    };

    let t_expr = if test.bench {
        quote_expr!(cx.ext_cx, self::extra::test::StaticBenchFn($fn_expr) )
    } else {
        quote_expr!(cx.ext_cx, self::extra::test::StaticTestFn($fn_expr) )
    };

    let ignore_expr = if test.ignore {
        quote_expr!(cx.ext_cx, true )
    } else {
        quote_expr!(cx.ext_cx, false )
    };

    let fail_expr = if test.should_fail {
        quote_expr!(cx.ext_cx, true )
    } else {
        quote_expr!(cx.ext_cx, false )
    };

    let e = quote_expr!(cx.ext_cx,
        self::extra::test::TestDescAndFn {
            desc: self::extra::test::TestDesc {
                name: self::extra::test::StaticTestName($name_expr),
                ignore: $ignore_expr,
                should_fail: $fail_expr
            },
            testfn: $t_expr,
        }
    );
    e
}
<commit_msg>librustc: De-`@mut` `TestCtxt::testfns`<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Code that generates a test runner to run all the tests in a crate

use driver::session;
use front::config;

use std::cell::RefCell;
use std::vec;
use syntax::ast_util::*;
use syntax::attr::AttrMetaMethods;
use syntax::attr;
use syntax::codemap::{dummy_sp, Span, ExpnInfo, NameAndSpan, MacroAttribute};
use syntax::codemap;
use syntax::ext::base::ExtCtxt;
use syntax::fold::ast_fold;
use syntax::fold;
use syntax::opt_vec;
use syntax::print::pprust;
use syntax::{ast, ast_util};
use syntax::util::small_vector::SmallVector;

struct Test {
    span: Span,
    path: ~[ast::Ident],
    bench: bool,
    ignore: bool,
    should_fail: bool
}

struct TestCtxt {
    sess: session::Session,
    path: RefCell<~[ast::Ident]>,
    ext_cx: @ExtCtxt,
    testfns: RefCell<~[Test]>,
    is_extra: bool,
    config: ast::CrateConfig,
}

// Traverse the crate, collecting all the test functions, eliding any
// existing main functions, and synthesizing a main test harness
pub fn modify_for_testing(sess: session::Session,
                          crate: ast::Crate) -> ast::Crate {
    // We generate the test harness when building in the 'test'
    // configuration, either with the '--test' or '--cfg test'
    // command line options.
    let should_test = attr::contains_name(crate.config, "test");

    if should_test {
        generate_test_harness(sess, crate)
    } else {
        strip_test_functions(crate)
    }
}

struct TestHarnessGenerator {
    cx: @mut TestCtxt,
}

impl fold::ast_fold for TestHarnessGenerator {
    fn fold_crate(&self, c: ast::Crate) -> ast::Crate {
        let folded = fold::noop_fold_crate(c, self);

        // Add a special __test module to the crate that will contain code
        // generated for the test harness
        ast::Crate {
            module: add_test_module(self.cx, &folded.module),
            .. folded
        }
    }

    fn fold_item(&self, i: @ast::item) -> SmallVector<@ast::item> {
        {
            let mut path = self.cx.path.borrow_mut();
            path.get().push(i.ident);
        }
        debug!("current path: {}",
               ast_util::path_name_i(self.cx.path.get()));

        if is_test_fn(self.cx, i) || is_bench_fn(i) {
            match i.node {
                ast::item_fn(_, purity, _, _, _)
                    if purity == ast::unsafe_fn => {
                    let sess = self.cx.sess;
                    sess.span_fatal(i.span,
                                    "unsafe functions cannot be used for \
                                     tests");
                }
                _ => {
                    debug!("this is a test function");
                    let test = Test {
                        span: i.span,
                        path: self.cx.path.get(),
                        bench: is_bench_fn(i),
                        ignore: is_ignored(self.cx, i),
                        should_fail: should_fail(i)
                    };
                    {
                        let mut testfns = self.cx.testfns.borrow_mut();
                        testfns.get().push(test);
                    }
                    // debug!("have {} test/bench functions",
                    //        cx.testfns.len());
                }
            }
        }

        let res = fold::noop_fold_item(i, self);
        {
            let mut path = self.cx.path.borrow_mut();
            path.get().pop();
        }
        res
    }

    fn fold_mod(&self, m: &ast::_mod) -> ast::_mod {
        // Remove any #[main] from the AST so it doesn't clash with
        // the one we're going to add. Only if compiling an executable.

        fn nomain(cx: @mut TestCtxt, item: @ast::item) -> @ast::item {
            if !*cx.sess.building_library {
                @ast::item {
                    attrs: item.attrs.iter().filter_map(|attr| {
                        if "main" != attr.name() {
                            Some(*attr)
                        } else {
                            None
                        }
                    }).collect(),
                    .. (*item).clone()
                }
            } else {
                item
            }
        }

        let mod_nomain = ast::_mod {
            view_items: m.view_items.clone(),
            items: m.items.iter().map(|i| nomain(self.cx, *i)).collect(),
        };

        fold::noop_fold_mod(&mod_nomain, self)
    }
}

fn generate_test_harness(sess: session::Session, crate: ast::Crate)
                         -> ast::Crate {
    let cx: @mut TestCtxt = @mut TestCtxt {
        sess: sess,
        ext_cx: ExtCtxt::new(sess.parse_sess, sess.opts.cfg.clone()),
        path: RefCell::new(~[]),
        testfns: RefCell::new(~[]),
        is_extra: is_extra(&crate),
        config: crate.config.clone(),
    };

    let ext_cx = cx.ext_cx;
    ext_cx.bt_push(ExpnInfo {
        call_site: dummy_sp(),
        callee: NameAndSpan {
            name: @"test",
            format: MacroAttribute,
            span: None
        }
    });

    let fold = TestHarnessGenerator {
        cx: cx
    };
    let res = fold.fold_crate(crate);
    ext_cx.bt_pop();
    return res;
}

fn strip_test_functions(crate: ast::Crate) -> ast::Crate {
    // When not compiling with --test we should not compile the
    // #[test] functions
    config::strip_items(crate, |attrs| {
        !attr::contains_name(attrs, "test") &&
        !attr::contains_name(attrs, "bench")
    })
}

fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool {
    let has_test_attr = attr::contains_name(i.attrs, "test");

    fn has_test_signature(i: @ast::item) -> bool {
        match &i.node {
          &ast::item_fn(ref decl, _, _, ref generics, _) => {
            let no_output = match decl.output.node {
                ast::ty_nil => true,
                _ => false
            };
            decl.inputs.is_empty()
                && no_output
                && !generics.is_parameterized()
          }
          _ => false
        }
    }

    if has_test_attr && !has_test_signature(i) {
        let sess = cx.sess;
        sess.span_err(
            i.span,
            "functions used as tests must have signature fn() -> ()."
        );
    }

    return has_test_attr && has_test_signature(i);
}

fn is_bench_fn(i: @ast::item) -> bool {
    let has_bench_attr = attr::contains_name(i.attrs, "bench");

    fn has_test_signature(i: @ast::item) -> bool {
        match i.node {
            ast::item_fn(ref decl, _, _, ref generics, _) => {
                let input_cnt = decl.inputs.len();
                let no_output = match decl.output.node {
                    ast::ty_nil => true,
                    _ => false
                };
                let tparm_cnt = generics.ty_params.len();
                // NB: inadequate check, but we're running
                // well before resolve, can't get too deep.
                input_cnt == 1u
                    && no_output && tparm_cnt == 0u
            }
          _ => false
        }
    }

    return has_bench_attr && has_test_signature(i);
}

fn is_ignored(cx: @mut TestCtxt, i: @ast::item) -> bool {
    i.attrs.iter().any(|attr| {
        // check ignore(cfg(foo, bar))
        "ignore" == attr.name() && match attr.meta_item_list() {
            Some(ref cfgs) => attr::test_cfg(cx.config, cfgs.iter().map(|x| *x)),
            None => true
        }
    })
}

fn should_fail(i: @ast::item) -> bool {
    attr::contains_name(i.attrs, "should_fail")
}

fn add_test_module(cx: &TestCtxt, m: &ast::_mod) -> ast::_mod {
    let testmod = mk_test_module(cx);
    ast::_mod {
        items: vec::append_one(m.items.clone(), testmod),
        ..(*m).clone()
    }
}

/*

We're going to be building a module that looks more or less like:

mod __test {
  #[!resolve_unexported]
  extern mod extra (name = "extra", vers = "...");
  fn main() {
    #[main];
    extra::test::test_main_static(::os::args(), tests)
  }

  static tests : &'static [extra::test::TestDescAndFn] = &[
    ... the list of tests in the crate ...
  ];
}

*/

fn mk_std(cx: &TestCtxt) -> ast::view_item {
    let id_extra = cx.sess.ident_of("extra");
    let vi = if cx.is_extra {
        ast::view_item_use(
            ~[@nospan(ast::view_path_simple(id_extra,
                                            path_node(~[id_extra]),
                                            ast::DUMMY_NODE_ID))])
    } else {
        let mi = attr::mk_name_value_item_str(@"vers", @"0.9-pre");
        ast::view_item_extern_mod(id_extra, None, ~[mi], ast::DUMMY_NODE_ID)
    };
    ast::view_item {
        node: vi,
        attrs: ~[],
        vis: ast::public,
        span: dummy_sp()
    }
}

fn mk_test_module(cx: &TestCtxt) -> @ast::item {

    // Link to extra
    let view_items = ~[mk_std(cx)];

    // A constant vector of test descriptors.
    let tests = mk_tests(cx);

    // The synthesized main function which will call the console test runner
    // with our list of tests
    let mainfn = (quote_item!(cx.ext_cx,
        pub fn main() {
            #[main];
            extra::test::test_main_static(::std::os::args(), TESTS);
        }
    )).unwrap();

    let testmod = ast::_mod {
        view_items: view_items,
        items: ~[mainfn, tests],
    };
    let item_ = ast::item_mod(testmod);

    // This attribute tells resolve to let us call unexported functions
    let resolve_unexported_attr =
        attr::mk_attr(attr::mk_word_item(@"!resolve_unexported"));

    let item = ast::item {
        ident: cx.sess.ident_of("__test"),
        attrs: ~[resolve_unexported_attr],
        id: ast::DUMMY_NODE_ID,
        node: item_,
        vis: ast::public,
        span: dummy_sp(),
     };

    debug!("Synthetic test module:\n{}\n",
           pprust::item_to_str(&item, cx.sess.intr()));

    return @item;
}

fn nospan<T>(t: T) -> codemap::Spanned<T> {
    codemap::Spanned { node: t, span: dummy_sp() }
}

fn path_node(ids: ~[ast::Ident]) -> ast::Path {
    ast::Path {
        span: dummy_sp(),
        global: false,
        segments: ids.move_iter().map(|identifier| ast::PathSegment {
            identifier: identifier,
            lifetimes: opt_vec::Empty,
            types: opt_vec::Empty,
        }).collect()
    }
}

fn path_node_global(ids: ~[ast::Ident]) -> ast::Path {
    ast::Path {
        span: dummy_sp(),
        global: true,
        segments: ids.move_iter().map(|identifier| ast::PathSegment {
            identifier: identifier,
            lifetimes: opt_vec::Empty,
            types: opt_vec::Empty,
        }).collect()
    }
}

fn mk_tests(cx: &TestCtxt) -> @ast::item {
    // The vector of test_descs for this crate
    let test_descs = mk_test_descs(cx);

    (quote_item!(cx.ext_cx,
        pub static TESTS : &'static [self::extra::test::TestDescAndFn] =
            $test_descs
        ;
    )).unwrap()
}

fn is_extra(crate: &ast::Crate) -> bool {
    match attr::find_pkgid(crate.attrs) {
        Some(ref s) if "extra" == s.name => true,
        _ => false
    }
}

fn mk_test_descs(cx: &TestCtxt) -> @ast::Expr {
    let mut descs = ~[];
    {
        let testfns = cx.testfns.borrow();
        debug!("building test vector from {} tests", testfns.get().len());
        for test in testfns.get().iter() {
            descs.push(mk_test_desc_and_fn_rec(cx, test));
        }
    }

    let inner_expr = @ast::Expr {
        id: ast::DUMMY_NODE_ID,
        node: ast::ExprVec(descs, ast::MutImmutable),
        span: dummy_sp(),
    };

    @ast::Expr {
        id: ast::DUMMY_NODE_ID,
        node: ast::ExprVstore(inner_expr, ast::ExprVstoreSlice),
        span: dummy_sp(),
    }
}

fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::Expr {
    let span = test.span;
    let path = test.path.clone();

    debug!("encoding {}", ast_util::path_name_i(path));

    let name_lit: ast::lit =
        nospan(ast::lit_str(ast_util::path_name_i(path).to_managed(), ast::CookedStr));

    let name_expr = @ast::Expr {
          id: ast::DUMMY_NODE_ID,
          node: ast::ExprLit(@name_lit),
          span: span
    };

    let fn_path = path_node_global(path);

    let fn_expr = @ast::Expr {
        id: ast::DUMMY_NODE_ID,
        node: ast::ExprPath(fn_path),
        span: span,
    };

    let t_expr = if test.bench {
        quote_expr!(cx.ext_cx, self::extra::test::StaticBenchFn($fn_expr) )
    } else {
        quote_expr!(cx.ext_cx, self::extra::test::StaticTestFn($fn_expr) )
    };

    let ignore_expr = if test.ignore {
        quote_expr!(cx.ext_cx, true )
    } else {
        quote_expr!(cx.ext_cx, false )
    };

    let fail_expr = if test.should_fail {
        quote_expr!(cx.ext_cx, true )
    } else {
        quote_expr!(cx.ext_cx, false )
    };

    let e = quote_expr!(cx.ext_cx,
        self::extra::test::TestDescAndFn {
            desc: self::extra::test::TestDesc {
                name: self::extra::test::StaticTestName($name_expr),
                ignore: $ignore_expr,
                should_fail: $fail_expr
            },
            testfn: $t_expr,
        }
    );
    e
}
<|endoftext|>


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

//! New recursive solver modeled on Chalk's recursive solver. Most of
//! the guts are broken up into modules; see the comments in those modules.

#![feature(crate_in_paths)]
#![feature(crate_visibility_modifier)]
#![feature(extern_prelude)]
#![feature(iterator_find_map)]
#![feature(in_band_lifetimes)]

#![recursion_limit="256"]

extern crate chalk_engine;
#[macro_use]
extern crate log;
#[macro_use]
extern crate rustc;
extern crate rustc_data_structures;
extern crate syntax;
extern crate syntax_pos;

mod chalk_context;
mod dropck_outlives;
mod evaluate_obligation;
mod implied_outlives_bounds;
mod normalize_projection_ty;
mod normalize_erasing_regions;
pub mod lowering;
mod type_op;

use rustc::ty::query::Providers;

pub fn provide(p: &mut Providers) {
    dropck_outlives::provide(p);
    evaluate_obligation::provide(p);
    implied_outlives_bounds::provide(p);
    lowering::provide(p);
    normalize_projection_ty::provide(p);
    normalize_erasing_regions::provide(p);
    type_op::provide(p);
}
<commit_msg>[nll] librustc_traits: enable feature(nll) for bootstrap<commit_after>// Copyright 2014 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.

//! New recursive solver modeled on Chalk's recursive solver. Most of
//! the guts are broken up into modules; see the comments in those modules.

#![feature(crate_in_paths)]
#![feature(crate_visibility_modifier)]
#![feature(extern_prelude)]
#![feature(iterator_find_map)]
#![feature(in_band_lifetimes)]
#![cfg_attr(not(stage0), feature(nll))]

#![recursion_limit="256"]

extern crate chalk_engine;
#[macro_use]
extern crate log;
#[macro_use]
extern crate rustc;
extern crate rustc_data_structures;
extern crate syntax;
extern crate syntax_pos;

mod chalk_context;
mod dropck_outlives;
mod evaluate_obligation;
mod implied_outlives_bounds;
mod normalize_projection_ty;
mod normalize_erasing_regions;
pub mod lowering;
mod type_op;

use rustc::ty::query::Providers;

pub fn provide(p: &mut Providers) {
    dropck_outlives::provide(p);
    evaluate_obligation::provide(p);
    implied_outlives_bounds::provide(p);
    lowering::provide(p);
    normalize_projection_ty::provide(p);
    normalize_erasing_regions::provide(p);
    type_op::provide(p);
}
<|endoftext|>


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

// Perlin noise benchmark from https://gist.github.com/1170424

use std::f64;
use std::rand::Rng;
use std::rand;

struct Vec2 {
    x: f32,
    y: f32,
}

#[inline(always)]
fn lerp(a: f32, b: f32, v: f32) -> f32 { a * (1.0 - v) + b * v }

#[inline(always)]
fn smooth(v: f32) -> f32 { v * v * (3.0 - 2.0 * v) }

fn random_gradient<R:Rng>(r: &mut R) -> Vec2 {
    let v = 2.0 * f64::consts::PI * r.gen();
    Vec2 {
        x: v.cos() as f32,
        y: v.sin() as f32,
    }
}

fn gradient(orig: Vec2, grad: Vec2, p: Vec2) -> f32 {
    let sp = Vec2 {x: p.x - orig.x, y: p.y - orig.y};
    grad.x * sp.x + grad.y * sp.y
}

struct Noise2DContext {
    rgradients: [Vec2, ..256],
    permutations: [int, ..256],
}

impl Noise2DContext {
    pub fn new() -> Noise2DContext {
        let mut r = rand::rng();
        let mut rgradients = [ Vec2 { x: 0.0, y: 0.0 }, ..256 ];
        for i in range(0, 256) {
            rgradients[i] = random_gradient(&mut r);
        }
        let mut permutations = [ 0, ..256 ];
        for i in range(0, 256) {
            permutations[i] = i;
        }
        r.shuffle_mut(permutations);

        Noise2DContext {
            rgradients: rgradients,
            permutations: permutations,
        }
    }

    #[inline(always)]
    pub fn get_gradient(&self, x: int, y: int) -> Vec2 {
        let idx = self.permutations[x & 255] + self.permutations[y & 255];
        self.rgradients[idx & 255]
    }

    #[inline]
    pub fn get_gradients(&self,
                         gradients: &mut [Vec2, ..4],
                         origins: &mut [Vec2, ..4],
                         x: f32,
                         y: f32) {
        let x0f = x.floor();
        let y0f = y.floor();
        let x0 = x0f as int;
        let y0 = y0f as int;
        let x1 = x0 + 1;
        let y1 = y0 + 1;

        gradients[0] = self.get_gradient(x0, y0);
        gradients[1] = self.get_gradient(x1, y0);
        gradients[2] = self.get_gradient(x0, y1);
        gradients[3] = self.get_gradient(x1, y1);

        origins[0] = Vec2 {x: x0f + 0.0, y: y0f + 0.0};
        origins[1] = Vec2 {x: x0f + 1.0, y: y0f + 0.0};
        origins[2] = Vec2 {x: x0f + 0.0, y: y0f + 1.0};
        origins[3] = Vec2 {x: x0f + 1.0, y: y0f + 1.0};
    }

    #[inline]
    pub fn get(&self, x: f32, y: f32) -> f32 {
        let p = Vec2 {x: x, y: y};
        let mut gradients = [ Vec2 { x: 0.0, y: 0.0 }, ..4 ];
        let mut origins = [ Vec2 { x: 0.0, y: 0.0 }, ..4 ];
        self.get_gradients(&mut gradients, &mut origins, x, y);
        let v0 = gradient(origins[0], gradients[0], p);
        let v1 = gradient(origins[1], gradients[1], p);
        let v2 = gradient(origins[2], gradients[2], p);
        let v3 = gradient(origins[3], gradients[3], p);
        let fx = smooth(x - origins[0].x);
        let vx0 = lerp(v0, v1, fx);
        let vx1 = lerp(v2, v3, fx);
        let fy = smooth(y - origins[0].y);
        lerp(vx0, vx1, fy)
    }
}

fn main() {
    let symbols = [" ", "░", "▒", "▓", "█", "█"];
    let mut pixels = [0f32, ..256*256];
    let n2d = ~Noise2DContext::new();
    for _ in range(0, 100u) {
        for y in range(0, 256) {
            for x in range(0, 256) {
                let v = n2d.get(
                    x as f32 * 0.1f32,
                    y as f32 * 0.1f32
                ) * 0.5f32 + 0.5f32;
                pixels[y*256+x] = v;
            };
        };
    };

    for y in range(0, 256) {
        for x in range(0, 256) {
            print!("{}", symbols[(pixels[y*256+x] / 0.2f32) as int]);
        }
        println!("");
    }
}
<commit_msg>auto merge of #12270 : bstrie/rust/pnoise, r=huonw<commit_after>// Copyright 2014 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.

// Multi-language Perlin noise benchmark.
// See https://github.com/nsf/pnoise for timings and alternative implementations.

use std::f32::consts::PI;
use std::rand::{Rng, StdRng};

struct Vec2 {
    x: f32,
    y: f32,
}

fn lerp(a: f32, b: f32, v: f32) -> f32 { a * (1.0 - v) + b * v }

fn smooth(v: f32) -> f32 { v * v * (3.0 - 2.0 * v) }

fn random_gradient<R: Rng>(r: &mut R) -> Vec2 {
    let v = PI * 2.0 * r.gen();
    Vec2 { x: v.cos(), y: v.sin() }
}

fn gradient(orig: Vec2, grad: Vec2, p: Vec2) -> f32 {
    (p.x - orig.x) * grad.x + (p.y - orig.y) * grad.y
}

struct Noise2DContext {
    rgradients: [Vec2, ..256],
    permutations: [i32, ..256],
}

impl Noise2DContext {
    fn new() -> Noise2DContext {
        let mut rng = StdRng::new();

        let mut rgradients = [Vec2 { x: 0.0, y: 0.0 }, ..256];
        for x in rgradients.mut_iter() {
            *x = random_gradient(&mut rng);
        }

        let mut permutations = [0i32, ..256];
        for (i, x) in permutations.mut_iter().enumerate() {
            *x = i as i32;
        }
        rng.shuffle_mut(permutations);

        Noise2DContext { rgradients: rgradients, permutations: permutations }
    }

    fn get_gradient(&self, x: i32, y: i32) -> Vec2 {
        let idx = self.permutations[x & 255] + self.permutations[y & 255];
        self.rgradients[idx & 255]
    }

    fn get_gradients(&self, x: f32, y: f32) -> ([Vec2, ..4], [Vec2, ..4]) {
        let x0f = x.floor();
        let y0f = y.floor();
        let x1f = x0f + 1.0;
        let y1f = y0f + 1.0;

        let x0 = x0f as i32;
        let y0 = y0f as i32;
        let x1 = x0 + 1;
        let y1 = y0 + 1;

        ([self.get_gradient(x0, y0), self.get_gradient(x1, y0),
          self.get_gradient(x0, y1), self.get_gradient(x1, y1)],
         [Vec2 { x: x0f, y: y0f }, Vec2 { x: x1f, y: y0f },
          Vec2 { x: x0f, y: y1f }, Vec2 { x: x1f, y: y1f }])
    }

    fn get(&self, x: f32, y: f32) -> f32 {
        let p = Vec2 {x: x, y: y};
        let (gradients, origins) = self.get_gradients(x, y);

        let v0 = gradient(origins[0], gradients[0], p);
        let v1 = gradient(origins[1], gradients[1], p);
        let v2 = gradient(origins[2], gradients[2], p);
        let v3 = gradient(origins[3], gradients[3], p);

        let fx = smooth(x - origins[0].x);
        let vx0 = lerp(v0, v1, fx);
        let vx1 = lerp(v2, v3, fx);
        let fy = smooth(y - origins[0].y);

        lerp(vx0, vx1, fy)
    }
}

fn main() {
    let symbols = [' ', '░', '▒', '▓', '█', '█'];
    let mut pixels = [0f32, ..256*256];
    let n2d = Noise2DContext::new();

    for _ in range(0, 100) {
        for y in range(0, 256) {
            for x in range(0, 256) {
                let v = n2d.get(x as f32 * 0.1, y as f32 * 0.1);
                pixels[y*256+x] = v * 0.5 + 0.5;
            }
        }
    }

    for y in range(0, 256) {
        for x in range(0, 256) {
            let idx = (pixels[y*256+x] / 0.2) as uint;
            print!("{:c}", symbols[idx]);
        }
        print!("\n");
    }
}
<|endoftext|>


<commit_before>use crate::Msg;
use seed::prelude::*;
use web_sys::{HtmlInputElement};

fn trial_divide(n: u64, max: u64) -> u64 {
    // Trial divides the positive integer n by the primes from 2 to max
    // Returns the first prime divisor found, or 0 if none found
    // Note: if n < max^2 is a prime, then n will be returned.
    if n % 2 == 0 {
        2
    } else if n % 3 == 0 {
        3
    } else {
        // No need to go past the square root of our number
        let sqrt: u64 = (n as f64).sqrt().floor() as u64;
        let stop = if sqrt > max { max } else { sqrt };
        // Okay, lets "wheel factor" alternately adding 2 and 4
        let mut di = 2;
        let mut i = 5;
        while i <= stop {
            if n % i == 0 {
                return i;
            }
            i += di;
            di = 6 - di;
        }
        if n >= max * max {
            0
        } else {
            n
        }
    }
}

// modadd(a,b,N) finds a+b (mod N) where a, b, and N can be
// up to (2^53-1)/2.  Might up this to 2^53-1 eventually...
fn modadd(a: u64, b: u64, n: u64) -> u64 {
    // When the integers a, b satisfy a+b > 2^53-1, then (a+b)%N is wrong
    // so we add this routine to allow us to reach a, b = 2^53-1.
    if a + b > 9007199254740991 {
        // Could reduce a and b (mod N) here, but assuming that has already been done
        // won't hurt if not... subtract 2^52 from one, 2^52-1 from the other and the
        // add it back modulo N (MaxInt+1)
        let t = ((a - 4503599627370496) + (b - 4503599627370495)) % n;
        return t + (9007199254740991 % n);
    }
    // Usual case: a + b is not too large:
    (a + b) % n
}

fn modmult(mut a: u64, mut b: u64, n: u64) -> u64 {
    if a > n {
        a = a % n;
    }
    if b > n {
        b = b % n;
    }
    if a * b <= 9007199254740991 {
        return (a * b) % n;
    } else {
        if b > a {
            return modmult(b.clone(), a, n);
        }

        // Right to left binary multiplication
        let mut t = 0;
        let mut f = a;
        while b > 1 {
            if (b & 1) == 1 {
                t = modadd(t, f, n);
            }
            //TODO: bitshift might be cleaner and faster
            b = (b as f64 / 2.0).floor() as u64;
            f = modadd(f, f, n);
        }
        t = modadd(t, f, n);
        return t;
    }
}

// modpow(a,exp,N) finds a^exp (mod N) where a, b, and N are
// limited by modmult
fn modpow(a: u64, mut exp: u64, n: u64) -> u64 {
    if exp == 0 {
        return 1;
    }

    // Right to left binary exponentiation
    let mut t = 1;
    let mut f = a;
    while exp > 1 {
        if (exp & 1) == 1 {
            // if exponent is odd
            t = modmult(t, f, n);
        }
        exp = (exp as f64 / 2.0).floor() as u64;
        f = modmult(f, f, n);
    }
    t = modmult(t, f, n);
    return t;
}

// sprp(N,a) checks if N (odd!) is a strong probable prime base a
// (returns true or false)
fn sprp(n: u64, a: u64) -> bool {
    let mut d = n - 1;
    let mut s = 1; // Assumes n is odd!
    loop {
        d = (d >> 2) & 1;
        if d == 0 {
            break;
        }
        s += 1;
    }
    // Now n-1 = d*2^s with d odd
    let mut b = modpow(a, d, n);
    if b == 1 {
        return true;
    }
    if b + 1 == n {
        return true;
    }
    while s > 1 {
        b = modmult(b, b, n);
        if b + 1 == n {
            return true;
        }
        s = s - 1;
    }
    return false;
}

pub struct Check {
    pub is_prime: bool,
    pub result: String,
}

pub fn check(input: String) -> Check {
    let trial_limit = 1300; // Should be bigger, like 10000
    let n: u64 = input.parse::<u64>().unwrap();
    let result;
    let mut is_prime = false;

    if n > 9007199254740991 {
        result = "Sorry, this routine will only handle integers below 9007199254740991.".to_owned();
    } else if n == 1 {
        result = "The number 1 is neither prime or composite (it is the multiplicative identity)."
            .to_owned();
    } else if n < 1 {
        result =
            "We usually restrict the terms prime and composite to positive integers".to_owned();
    } else {
        // Okay, n is of a resonable size, lets trial divide
        let i = trial_divide(n, trial_limit);
        if i > 0 && i != n {
            result = format!("{} is not a prime! It is {} * {}", n, i, n / i);
        } else if n < trial_limit * trial_limit {
            result = format!("{} is a (proven) prime!", n);
            is_prime = true;
        } else if sprp(n, 2)
            && sprp(n, 3)
            && sprp(n, 5)
            && sprp(n, 7)
            && sprp(n, 11)
            && sprp(n, 13)
            && sprp(n, 17)
        {
            // Some of these tests are unnecessary for small numbers, but for
            // small numbers they are quick anyway.
            if n < 341550071728321 {
                result = format!("{} is a (proven) prime.", n);
                is_prime = true;
            } else if n == 341550071728321 {
                result = format!("{} is not a prime! It is 10670053 * 32010157.", n);
            } else {
                result = format!(
                    "{} is probably a prime (it is a sprp bases 2, 3, 5, 7, 11, 13 and  17).",
                    n
                );
                is_prime = true;
            };
        } else {
            result = format!(
                "{} is (proven) composite (failed sprp test base {}).",
                n, 17
            );
        };
    };

    return Check{is_prime, result};
}

pub fn listy(start_number: u64, number_of_primes: u64) -> String {
    let mut i = 0;
    let mut j = start_number;
    let mut list: String = "".to_string();
    while i < number_of_primes {
        let result = check(j.to_string());
        if result.is_prime == true {
            list = list + &result.result + "\n";
            i += 1;
        }
        j += 1;
    }
    list
}

pub fn go_crunch() -> () {
    let window = web_sys::window().expect("no global `window` exists");
    let document = window.document().expect("should have a document on window");

    let el_input_value = document
        .get_element_by_id("input")
        .unwrap()
        .dyn_into::<HtmlInputElement>()
        .unwrap()
        .value();
    let el_output_textarea = document
        .get_element_by_id("prime_check_output")
        .expect("missing output textarea");
    el_output_textarea.set_inner_html(&check(el_input_value).result);
    ()
}

pub fn go_list() {
    let window = web_sys::window().expect("no global `window` exists");
    let document = window.document().expect("should have a document on window");

    let el_start_value = document
        .get_element_by_id("start")
        .unwrap()
        .dyn_into::<HtmlInputElement>()
        .unwrap()
        .value();
    let el_primes_value = document
        .get_element_by_id("primes")
        .unwrap()
        .dyn_into::<HtmlInputElement>()
        .unwrap()
        .value();
    let el_output_textarea = document
        .get_element_by_id("prime_check_list_output")
        .expect("missing output textarea");
    el_output_textarea.set_inner_html(&listy(
        el_start_value.parse::<u64>().unwrap(),
        el_primes_value.parse::<u64>().unwrap(),
    ));
    ()
}

pub fn render() -> Node<Msg> {
    div![
        h1!["Primality Test, Calculate Primes"],
        br![],
        br![],
        br![],
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                form![
                    attrs! {At::Id => "primetest", At::OnSubmit => "return false"},
                    "Tool is limited to checking numbers upto 16 digits.",
                    br![],
                    br![],
                    "Is ",
                    input![
                        attrs! {At::Type => "number", At::Size => "19", At::Id => "input", At::Value => "31", At::MaxLength => "16"}
                    ],
                    " prime? ",
                    button![
                        "Check!",
                        mouse_ev("mouseup", move |_event| Msg::PrimalityChecker(go_crunch()))
                    ],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Id => "prime_check_output", At::Cols => 60, At::Rows => 2, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ],
        br![],
        br![],
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                form![
                    attrs! {At::Id => "primelist", At::OnSubmit => "return false"},
                    "This tool is limited to checking numbers upto 15 digits.",
                    br![],
                    br![],
                    "This will show ",
                    input![
                        attrs! {At::Type => "number", At::Size => "4", At::Id => "primes", At::Value => "5", At::MaxLength => "2"}
                    ],
                    " prime numbers after ",
                    input![
                        attrs! {At::Type => "number", At::Size => "19", At::Id => "start", At::Value => "31", At::MaxLength => "15"}
                    ],
                    " ",
                    button![
                        "Go!",
                        mouse_ev("mouseup", move |_event| Msg::PrimalityChecker(go_list()))
                    ],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Id => "prime_check_list_output", At::Cols => 60, At::Rows => 10, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ]
    ]
}

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

    #[test]
    fn trial_divide_test() {
        assert_eq!(trial_divide(2, 2), 2);
        assert_eq!(trial_divide(3, 4), 3);
        assert_eq!(trial_divide(30, 10000), 2);
        assert_eq!(trial_divide(7777771, 10000), 29);
        assert_eq!(trial_divide(7777771111111111, 10000), 11);
        //in the case of a prime
        assert_eq!(trial_divide(777777111111113, 10000), 0);
    }

    #[test]
    fn sprp_test() {
        assert_eq!(sprp(27, 5), false);
        assert_eq!(sprp(31, 7), true);
        assert_eq!(sprp(217, 7), false);
        assert_eq!(sprp(19, 13), true);
    }

    #[test]
    fn mod_pow_test() {
        assert_eq!(modpow(6,3,11), 7);
        assert_eq!(modpow(113,7,11), 9);
    }
}
<commit_msg>added unit tests for mod_mult()<commit_after>use crate::Msg;
use seed::prelude::*;
use web_sys::{HtmlInputElement};

fn trial_divide(n: u64, max: u64) -> u64 {
    // Trial divides the positive integer n by the primes from 2 to max
    // Returns the first prime divisor found, or 0 if none found
    // Note: if n < max^2 is a prime, then n will be returned.
    if n % 2 == 0 {
        2
    } else if n % 3 == 0 {
        3
    } else {
        // No need to go past the square root of our number
        let sqrt: u64 = (n as f64).sqrt().floor() as u64;
        let stop = if sqrt > max { max } else { sqrt };
        // Okay, lets "wheel factor" alternately adding 2 and 4
        let mut di = 2;
        let mut i = 5;
        while i <= stop {
            if n % i == 0 {
                return i;
            }
            i += di;
            di = 6 - di;
        }
        if n >= max * max {
            0
        } else {
            n
        }
    }
}

// modadd(a,b,N) finds a+b (mod N) where a, b, and N can be
// up to (2^53-1)/2.  Might up this to 2^53-1 eventually...
fn modadd(a: u64, b: u64, n: u64) -> u64 {
    // When the integers a, b satisfy a+b > 2^53-1, then (a+b)%N is wrong
    // so we add this routine to allow us to reach a, b = 2^53-1.
    if a + b > 9007199254740991 {
        // Could reduce a and b (mod N) here, but assuming that has already been done
        // won't hurt if not... subtract 2^52 from one, 2^52-1 from the other and the
        // add it back modulo N (MaxInt+1)
        let t = ((a - 4503599627370496) + (b - 4503599627370495)) % n;
        return t + (9007199254740991 % n);
    }
    // Usual case: a + b is not too large:
    (a + b) % n
}

fn modmult(mut a: u64, mut b: u64, n: u64) -> u64 {
    if a > n {
        a = a % n;
    }
    if b > n {
        b = b % n;
    }
    if a * b <= 9007199254740991 {
        return (a * b) % n;
    } else {
        if b > a {
            return modmult(b.clone(), a, n);
        }

        // Right to left binary multiplication
        let mut t = 0;
        let mut f = a;
        while b > 1 {
            if (b & 1) == 1 {
                t = modadd(t, f, n);
            }
            //TODO: bitshift might be cleaner and faster
            b = (b as f64 / 2.0).floor() as u64;
            f = modadd(f, f, n);
        }
        t = modadd(t, f, n);
        return t;
    }
}

// modpow(a,exp,N) finds a^exp (mod N) where a, b, and N are
// limited by modmult
fn modpow(a: u64, mut exp: u64, n: u64) -> u64 {
    if exp == 0 {
        return 1;
    }

    // Right to left binary exponentiation
    let mut t = 1;
    let mut f = a;
    while exp > 1 {
        if (exp & 1) == 1 {
            // if exponent is odd
            t = modmult(t, f, n);
        }
        exp = (exp as f64 / 2.0).floor() as u64;
        f = modmult(f, f, n);
    }
    t = modmult(t, f, n);
    return t;
}

// sprp(N,a) checks if N (odd!) is a strong probable prime base a
// (returns true or false)
fn sprp(n: u64, a: u64) -> bool {
    let mut d = n - 1;
    let mut s = 1; // Assumes n is odd!
    loop {
        d = (d >> 2) & 1;
        if d == 0 {
            break;
        }
        s += 1;
    }
    // Now n-1 = d*2^s with d odd
    let mut b = modpow(a, d, n);
    if b == 1 {
        return true;
    }
    if b + 1 == n {
        return true;
    }
    while s > 1 {
        b = modmult(b, b, n);
        if b + 1 == n {
            return true;
        }
        s = s - 1;
    }
    return false;
}

pub struct Check {
    pub is_prime: bool,
    pub result: String,
}

pub fn check(input: String) -> Check {
    let trial_limit = 1300; // Should be bigger, like 10000
    let n: u64 = input.parse::<u64>().unwrap();
    let result;
    let mut is_prime = false;

    if n > 9007199254740991 {
        result = "Sorry, this routine will only handle integers below 9007199254740991.".to_owned();
    } else if n == 1 {
        result = "The number 1 is neither prime or composite (it is the multiplicative identity)."
            .to_owned();
    } else if n < 1 {
        result =
            "We usually restrict the terms prime and composite to positive integers".to_owned();
    } else {
        // Okay, n is of a resonable size, lets trial divide
        let i = trial_divide(n, trial_limit);
        if i > 0 && i != n {
            result = format!("{} is not a prime! It is {} * {}", n, i, n / i);
        } else if n < trial_limit * trial_limit {
            result = format!("{} is a (proven) prime!", n);
            is_prime = true;
        } else if sprp(n, 2)
            && sprp(n, 3)
            && sprp(n, 5)
            && sprp(n, 7)
            && sprp(n, 11)
            && sprp(n, 13)
            && sprp(n, 17)
        {
            // Some of these tests are unnecessary for small numbers, but for
            // small numbers they are quick anyway.
            if n < 341550071728321 {
                result = format!("{} is a (proven) prime.", n);
                is_prime = true;
            } else if n == 341550071728321 {
                result = format!("{} is not a prime! It is 10670053 * 32010157.", n);
            } else {
                result = format!(
                    "{} is probably a prime (it is a sprp bases 2, 3, 5, 7, 11, 13 and  17).",
                    n
                );
                is_prime = true;
            };
        } else {
            result = format!(
                "{} is (proven) composite (failed sprp test base {}).",
                n, 17
            );
        };
    };

    return Check{is_prime, result};
}

pub fn listy(start_number: u64, number_of_primes: u64) -> String {
    let mut i = 0;
    let mut j = start_number;
    let mut list: String = "".to_string();
    while i < number_of_primes {
        let result = check(j.to_string());
        if result.is_prime == true {
            list = list + &result.result + "\n";
            i += 1;
        }
        j += 1;
    }
    list
}

pub fn go_crunch() -> () {
    let window = web_sys::window().expect("no global `window` exists");
    let document = window.document().expect("should have a document on window");

    let el_input_value = document
        .get_element_by_id("input")
        .unwrap()
        .dyn_into::<HtmlInputElement>()
        .unwrap()
        .value();
    let el_output_textarea = document
        .get_element_by_id("prime_check_output")
        .expect("missing output textarea");
    el_output_textarea.set_inner_html(&check(el_input_value).result);
    ()
}

pub fn go_list() {
    let window = web_sys::window().expect("no global `window` exists");
    let document = window.document().expect("should have a document on window");

    let el_start_value = document
        .get_element_by_id("start")
        .unwrap()
        .dyn_into::<HtmlInputElement>()
        .unwrap()
        .value();
    let el_primes_value = document
        .get_element_by_id("primes")
        .unwrap()
        .dyn_into::<HtmlInputElement>()
        .unwrap()
        .value();
    let el_output_textarea = document
        .get_element_by_id("prime_check_list_output")
        .expect("missing output textarea");
    el_output_textarea.set_inner_html(&listy(
        el_start_value.parse::<u64>().unwrap(),
        el_primes_value.parse::<u64>().unwrap(),
    ));
    ()
}

pub fn render() -> Node<Msg> {
    div![
        h1!["Primality Test, Calculate Primes"],
        br![],
        br![],
        br![],
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                form![
                    attrs! {At::Id => "primetest", At::OnSubmit => "return false"},
                    "Tool is limited to checking numbers upto 16 digits.",
                    br![],
                    br![],
                    "Is ",
                    input![
                        attrs! {At::Type => "number", At::Size => "19", At::Id => "input", At::Value => "31", At::MaxLength => "16"}
                    ],
                    " prime? ",
                    button![
                        "Check!",
                        mouse_ev("mouseup", move |_event| Msg::PrimalityChecker(go_crunch()))
                    ],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Id => "prime_check_output", At::Cols => 60, At::Rows => 2, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ],
        br![],
        br![],
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                form![
                    attrs! {At::Id => "primelist", At::OnSubmit => "return false"},
                    "This tool is limited to checking numbers upto 15 digits.",
                    br![],
                    br![],
                    "This will show ",
                    input![
                        attrs! {At::Type => "number", At::Size => "4", At::Id => "primes", At::Value => "5", At::MaxLength => "2"}
                    ],
                    " prime numbers after ",
                    input![
                        attrs! {At::Type => "number", At::Size => "19", At::Id => "start", At::Value => "31", At::MaxLength => "15"}
                    ],
                    " ",
                    button![
                        "Go!",
                        mouse_ev("mouseup", move |_event| Msg::PrimalityChecker(go_list()))
                    ],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Id => "prime_check_list_output", At::Cols => 60, At::Rows => 10, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ]
    ]
}

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

    #[test]
    fn trial_divide_test() {
        assert_eq!(trial_divide(2, 2), 2);
        assert_eq!(trial_divide(3, 4), 3);
        assert_eq!(trial_divide(30, 10000), 2);
        assert_eq!(trial_divide(7777771, 10000), 29);
        assert_eq!(trial_divide(7777771111111111, 10000), 11);
        //in the case of a prime
        assert_eq!(trial_divide(777777111111113, 10000), 0);
    }

    #[test]
    fn sprp_test() {
        assert_eq!(sprp(27, 5), false);
        assert_eq!(sprp(31, 7), true);
        assert_eq!(sprp(217, 7), false);
        assert_eq!(sprp(19, 13), true);
    }

    #[test]
    fn mod_pow_test() {
        assert_eq!(modpow(6,3,11), 7);
        assert_eq!(modpow(113,7,11), 9);
    }

    #[test]
    fn mod_mult_test() {
        assert_eq!(modmult(3,3,4), 1);
        assert_eq!(modmult(110,4,7), 6);
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, PartialEq)]
pub struct NumericLiteral(pub f64);

#[derive(Debug, PartialEq)]
pub struct StringLiteral<'a>(pub &'a str);

pub mod parsing {

    use nom::{IResult, digit, hex_digit, oct_digit};
    use parser::helpers::parsing::*;
    use parser::js::terminals::*;

    named!(pub numeric_literal<&str, NumericLiteral>, conv!(NumericLiteral(do_parse!(
        take_while_s!(is_whitespace) >>
        numeric_literal: alt!(
            decimal_literal
            |
            hex_integer_literal
            |
            octal_integer_literal
        ) >>
        (numeric_literal)
    ))));

    named!(decimal_literal<&str, f64>, do_parse!(
        dec_lit: recognize!(alt!(
            do_parse!(
                decimal_integer_literal >>
                do_parse!(
                    opt!(complete!(do_parse!(
                        tag_s!(".") >>
                        opt!(complete!(digit)) >>
                        ()
                    ))) >>
                    opt!(complete!(exponential_part)) >>
                    ()
                ) >>
                ()
            )
            |
            do_parse!(
                tag_s!(".") >>
                complete!(digit) >>
                opt!(complete!(exponential_part)) >>
                ()
            )
        )) >>
        (dec_lit.parse::<f64>().unwrap())
    ));

    named!(decimal_integer_literal<&str, &str>, recognize!(alt!(
        do_parse!(
            tag_s!("0") >>
            not!(digit) >>
            not!(tag_s!("x")) >>
            not!(tag_s!("X")) >>
            ()
        )
        |
        do_parse!(
            not!(tag_s!("0")) >>
            digit >>
            ()
        )
    )));

    named!(exponential_part<&str, &str>, recognize!(do_parse!(
        alt!(tag_s!("e") | tag_s!("E")) >>
        opt!(alt!(tag_s!("+") | tag_s!("-"))) >>
        digit >>
        ()
    )));

    named!(hex_integer_literal<&str, f64>, do_parse!(
        alt!(tag_s!("0x") | tag_s!("0X")) >>
        hex: hex_digit >>
        (i64::from_str_radix(hex, 16).unwrap() as f64)
    ));

    named!(octal_integer_literal<&str, f64>, do_parse!(
        tag_s!("0") >>
        octal: oct_digit >>
        (i64::from_str_radix(octal, 8).unwrap() as f64)
    ));

    named!(pub string_literal<&str, StringLiteral>, do_parse!(
        delimiter: alt!(
            keyword!("\"")
            |
            keyword!("'")
        ) >>
        string: take_until_s!(delimiter) >> // TODO: escape chars
        keyword!(delimiter) >>
        (StringLiteral(string))
    ));

    named!(pub identifier<&str, &str>, do_parse!(
        take_while_s!(is_whitespace) >>
        identifier: recognize!(do_parse!(
            xid_start >>
            many0!(xid_continue) >>
            ()
        )) >>
        (identifier)
    ));

    named!(pub js_identifier<&str, &str>, alt!(
        keyword!("property")
        |
        keyword!("signal")
        |
        keyword!("readonly")
        |
        keyword!("on")
        |
        keyword!("get")
        |
        keyword!("set")
        |
        identifier
    ));

    named!(pub reserved_identifier<&str, &str>, alt!(
        keyword!("break")
        |
        keyword!("case")
        |
        keyword!("catch")
        |
        keyword!("continue")
        |
        keyword!("default")
        |
        keyword!("delete")
        |
        keyword!("do")
        |
        keyword!("else")
        |
        keyword!("false")
        |
        keyword!("finally")
        |
        keyword!("for")
        |
        keyword!("function")
        |
        keyword!("if")
        |
        keyword!("in")
        |
        keyword!("instanceof")
        |
        keyword!("new")
        |
        keyword!("null")
        |
        keyword!("return")
        |
        keyword!("switch")
        |
        keyword!("this")
        |
        keyword!("throw")
        |
        keyword!("true")
        |
        keyword!("try")
        |
        keyword!("typeof")
        |
        keyword!("var")
        |
        keyword!("void")
        |
        keyword!("while")
        |
        keyword!("const")
        |
        keyword!("debugger")
        |
        keyword!("with")
    ));

    named!(pub property_identifier<&str, &str>, alt!(
        reserved_identifier
        |
        js_identifier
    ));

    named!(pub assignment_operator<&str, &str>, alt!(
        keyword!("=")
        |
        keyword!("*=")
        |
        keyword!("/=")
        |
        keyword!("%=")
        |
        keyword!("+=")
        |
        keyword!("-=")
        |
        keyword!("<<=")
        |
        keyword!(">>>=")
        |
        keyword!(">>=")
        |
        keyword!("&=")
        |
        keyword!("^=")
        |
        keyword!("|=")
    ));

    named!(pub automatic_semicolon<&str, &str>, alt!(
        keyword!(";")
        |
        peek!(line_terminator)
        |
        peek!(keyword!("}"))
        |
        eof
    ));

    fn eof(i: &str) -> IResult<&str, &str> {
        eof!(i,)
    }

    named!(pub line_terminator<&str, &str>, alt!(
        tag_s!("\r\n")
        |
        tag_s!("\n")
        |
        tag_s!("\u{2028}")
        |
        tag_s!("\u{2029}")
    ));

    #[cfg(test)]
    mod tests {
        use nom::{ErrorKind, Needed};
        use super::*;

        #[test]
        fn numeric_literal() {
            assert_eq!(super::numeric_literal(""), IResult::Incomplete(Needed::Size(1)));

            // Decimal
            assert_eq!(super::numeric_literal("42"), IResult::Done("", NumericLiteral(42_f64)));
            assert_eq!(super::numeric_literal("0"), IResult::Done("", NumericLiteral(0_f64)));
            assert_eq!(super::numeric_literal("42.42e-4"), IResult::Done("", NumericLiteral(42.42e-4_f64)));
            assert_eq!(super::numeric_literal(".42"), IResult::Done("", NumericLiteral(0.42_f64)));
            assert_eq!(super::numeric_literal("42."), IResult::Done("", NumericLiteral(42_f64)));

            assert_eq!(super::numeric_literal("+42"), IResult::Error(ErrorKind::Alt)); // Identity is unary expression
            assert_eq!(super::numeric_literal("-42"), IResult::Error(ErrorKind::Alt)); // Negation is unary expression
            assert_eq!(super::numeric_literal("."), IResult::Error(ErrorKind::Alt));

            // Octal
            assert_eq!(super::numeric_literal("042"), IResult::Done("", NumericLiteral(34_f64)));

            // Hex
            assert_eq!(super::numeric_literal("0x42"), IResult::Done("", NumericLiteral(66_f64)));
            assert_eq!(super::numeric_literal("0X42"), IResult::Done("", NumericLiteral(66_f64)));
        }

        #[test]
        fn string_literal() {
            assert_eq!(super::string_literal("\"hi\""), IResult::Done("", StringLiteral("hi")));
            assert_eq!(super::string_literal(" 'hi'"), IResult::Done("", StringLiteral("hi")));

            assert_eq!(super::string_literal(""), IResult::Incomplete(Needed::Size(1)));

            assert_eq!(super::string_literal("\"hi"), IResult::Error(ErrorKind::TakeUntil)); // FIXME: https://github.com/Geal/nom/issues/397
            assert_eq!(super::string_literal("'hi"), IResult::Error(ErrorKind::TakeUntil));
        }

    }
}<commit_msg>Add test case for numeric_literal<commit_after>#[derive(Debug, PartialEq)]
pub struct NumericLiteral(pub f64);

#[derive(Debug, PartialEq)]
pub struct StringLiteral<'a>(pub &'a str);

pub mod parsing {

    use nom::{IResult, digit, hex_digit, oct_digit};
    use parser::helpers::parsing::*;
    use parser::js::terminals::*;

    named!(pub numeric_literal<&str, NumericLiteral>, conv!(NumericLiteral(do_parse!(
        take_while_s!(is_whitespace) >>
        numeric_literal: alt!(
            decimal_literal
            |
            hex_integer_literal
            |
            octal_integer_literal
        ) >>
        (numeric_literal)
    ))));

    named!(decimal_literal<&str, f64>, do_parse!(
        dec_lit: recognize!(alt!(
            do_parse!(
                decimal_integer_literal >>
                do_parse!(
                    opt!(complete!(do_parse!(
                        tag_s!(".") >>
                        opt!(complete!(digit)) >>
                        ()
                    ))) >>
                    opt!(complete!(exponential_part)) >>
                    ()
                ) >>
                ()
            )
            |
            do_parse!(
                tag_s!(".") >>
                complete!(digit) >>
                opt!(complete!(exponential_part)) >>
                ()
            )
        )) >>
        (dec_lit.parse::<f64>().unwrap())
    ));

    named!(decimal_integer_literal<&str, &str>, recognize!(alt!(
        do_parse!(
            tag_s!("0") >>
            not!(digit) >>
            not!(tag_s!("x")) >>
            not!(tag_s!("X")) >>
            ()
        )
        |
        do_parse!(
            not!(tag_s!("0")) >>
            digit >>
            ()
        )
    )));

    named!(exponential_part<&str, &str>, recognize!(do_parse!(
        alt!(tag_s!("e") | tag_s!("E")) >>
        opt!(alt!(tag_s!("+") | tag_s!("-"))) >>
        digit >>
        ()
    )));

    named!(hex_integer_literal<&str, f64>, do_parse!(
        alt!(tag_s!("0x") | tag_s!("0X")) >>
        hex: hex_digit >>
        (i64::from_str_radix(hex, 16).unwrap() as f64)
    ));

    named!(octal_integer_literal<&str, f64>, do_parse!(
        tag_s!("0") >>
        octal: oct_digit >>
        (i64::from_str_radix(octal, 8).unwrap() as f64)
    ));

    named!(pub string_literal<&str, StringLiteral>, do_parse!(
        delimiter: alt!(
            keyword!("\"")
            |
            keyword!("'")
        ) >>
        string: take_until_s!(delimiter) >> // TODO: escape chars
        keyword!(delimiter) >>
        (StringLiteral(string))
    ));

    named!(pub identifier<&str, &str>, do_parse!(
        take_while_s!(is_whitespace) >>
        identifier: recognize!(do_parse!(
            xid_start >>
            many0!(xid_continue) >>
            ()
        )) >>
        (identifier)
    ));

    named!(pub js_identifier<&str, &str>, alt!(
        keyword!("property")
        |
        keyword!("signal")
        |
        keyword!("readonly")
        |
        keyword!("on")
        |
        keyword!("get")
        |
        keyword!("set")
        |
        identifier
    ));

    named!(pub reserved_identifier<&str, &str>, alt!(
        keyword!("break")
        |
        keyword!("case")
        |
        keyword!("catch")
        |
        keyword!("continue")
        |
        keyword!("default")
        |
        keyword!("delete")
        |
        keyword!("do")
        |
        keyword!("else")
        |
        keyword!("false")
        |
        keyword!("finally")
        |
        keyword!("for")
        |
        keyword!("function")
        |
        keyword!("if")
        |
        keyword!("in")
        |
        keyword!("instanceof")
        |
        keyword!("new")
        |
        keyword!("null")
        |
        keyword!("return")
        |
        keyword!("switch")
        |
        keyword!("this")
        |
        keyword!("throw")
        |
        keyword!("true")
        |
        keyword!("try")
        |
        keyword!("typeof")
        |
        keyword!("var")
        |
        keyword!("void")
        |
        keyword!("while")
        |
        keyword!("const")
        |
        keyword!("debugger")
        |
        keyword!("with")
    ));

    named!(pub property_identifier<&str, &str>, alt!(
        reserved_identifier
        |
        js_identifier
    ));

    named!(pub assignment_operator<&str, &str>, alt!(
        keyword!("=")
        |
        keyword!("*=")
        |
        keyword!("/=")
        |
        keyword!("%=")
        |
        keyword!("+=")
        |
        keyword!("-=")
        |
        keyword!("<<=")
        |
        keyword!(">>>=")
        |
        keyword!(">>=")
        |
        keyword!("&=")
        |
        keyword!("^=")
        |
        keyword!("|=")
    ));

    named!(pub automatic_semicolon<&str, &str>, alt!(
        keyword!(";")
        |
        peek!(line_terminator)
        |
        peek!(keyword!("}"))
        |
        eof
    ));

    fn eof(i: &str) -> IResult<&str, &str> {
        eof!(i,)
    }

    named!(pub line_terminator<&str, &str>, alt!(
        tag_s!("\r\n")
        |
        tag_s!("\n")
        |
        tag_s!("\u{2028}")
        |
        tag_s!("\u{2029}")
    ));

    #[cfg(test)]
    mod tests {
        use nom::{ErrorKind, Needed};
        use super::*;

        #[test]
        fn numeric_literal() {
            assert_eq!(super::numeric_literal(""), IResult::Incomplete(Needed::Size(1)));

            // Decimal
            assert_eq!(super::numeric_literal("42"), IResult::Done("", NumericLiteral(42_f64)));
            assert_eq!(super::numeric_literal(" 42"), IResult::Done("", NumericLiteral(42_f64)));
            assert_eq!(super::numeric_literal("0"), IResult::Done("", NumericLiteral(0_f64)));
            assert_eq!(super::numeric_literal("42.42e-4"), IResult::Done("", NumericLiteral(42.42e-4_f64)));
            assert_eq!(super::numeric_literal(".42"), IResult::Done("", NumericLiteral(0.42_f64)));
            assert_eq!(super::numeric_literal("42."), IResult::Done("", NumericLiteral(42_f64)));

            assert_eq!(super::numeric_literal("+42"), IResult::Error(ErrorKind::Alt)); // Identity is unary expression
            assert_eq!(super::numeric_literal("-42"), IResult::Error(ErrorKind::Alt)); // Negation is unary expression
            assert_eq!(super::numeric_literal("."), IResult::Error(ErrorKind::Alt));

            // Octal
            assert_eq!(super::numeric_literal("042"), IResult::Done("", NumericLiteral(34_f64)));

            // Hex
            assert_eq!(super::numeric_literal("0x42"), IResult::Done("", NumericLiteral(66_f64)));
            assert_eq!(super::numeric_literal("0X42"), IResult::Done("", NumericLiteral(66_f64)));
        }

        #[test]
        fn string_literal() {
            assert_eq!(super::string_literal("\"hi\""), IResult::Done("", StringLiteral("hi")));
            assert_eq!(super::string_literal(" 'hi'"), IResult::Done("", StringLiteral("hi")));

            assert_eq!(super::string_literal(""), IResult::Incomplete(Needed::Size(1)));

            assert_eq!(super::string_literal("\"hi"), IResult::Error(ErrorKind::TakeUntil)); // FIXME: https://github.com/Geal/nom/issues/397
            assert_eq!(super::string_literal("'hi"), IResult::Error(ErrorKind::TakeUntil));
        }

    }
}<|endoftext|>


<commit_before>use std::sync::{Arc, Mutex};

use uuid::Uuid;
use postgres::{Connection, TlsMode};

use crate::api::query::Query;

pub struct SiteDB {
    conn: Arc<Mutex<Connection>>,
}

impl SiteDB {
    pub fn new(connection_string: &str) -> SiteDB {
        let conn = match Connection::connect(connection_string, TlsMode::None) {
            Ok(conn) => conn,
            Err(err) => panic!("failed to connect using: {}, err: {}",
                               connection_string, err)
        };

        SiteDB {
            conn: Arc::new(Mutex::new(conn)),
        }
    }

    pub fn query_by_id(&self, uuid: &Uuid) -> Option<Query> {
        let rs = match self.conn.lock().as_mut().unwrap().query("SELECT query_json FROM query WHERE id = $1",
                                       &[uuid])
        {
            Ok(rs) => rs,
            Err(_) => return None,
        };

        if rs.len() > 0 {
            let query_value: Option<String> = rs.get(0).get(0);

            let query: Query = match serde_json::from_str(&query_value.unwrap()) {
                Ok(v) => v,
                Err(_) => return None,
            };

            return Some(query);
        }

        None
    }

    pub fn id_from_query(&self, query: &Query) -> Option<Uuid> {
        let query_value: String = match serde_json::value::to_value(query) {
            Ok(v) => v.to_string(),
            Err(err) => {
                eprint!("error converting query to string: {:?}\n", err);
                return None;
            }
        };

        let rs = match self.conn.lock().as_mut().unwrap().query("SELECT id::uuid FROM query WHERE digest(query_json, 'sha256') = digest($1, 'sha256');",
                                       &[&query_value])
        {
            Ok(rs) => rs,
            Err(err) => {
                eprint!("error querying in id_from_query(): {:?}\n", err);
                return None;
            }
        };

        if rs.len() > 0 {
            let id: Uuid = rs.get(0).get("id");
            Some(id)
        } else {
            eprint!("query not in DB: {}\n", query_value);
            None
        }
    }

    pub fn save_query(&self, uuid: &Uuid, query: &Query) -> Result<(), String> {
        let mut locked_conn = self.conn.lock();
        let trans = match locked_conn.as_mut().unwrap().transaction() {
            Ok(t) => t,
            Err(e) => return Err(format!("couldn't begin transaction: {}", e)),
        };

        let serde_value: String = match serde_json::value::to_value(&query) {
            Ok(v) => v.to_string(),
            Err(e) => return Err(format!("serde error: {}", e)),
        };

        match trans.execute("INSERT INTO query(id, query_json) values ($1, $2)",
                            &[uuid, &serde_value]) {
            Ok(_) => (),
            Err(e) => return Err(format!("Error executing query: {}", e)),
        };

        match trans.commit() {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{}", e)),
        }
    }
}
<commit_msg>Remove unneeded debug message while querying<commit_after>use std::sync::{Arc, Mutex};

use uuid::Uuid;
use postgres::{Connection, TlsMode};

use crate::api::query::Query;

pub struct SiteDB {
    conn: Arc<Mutex<Connection>>,
}

impl SiteDB {
    pub fn new(connection_string: &str) -> SiteDB {
        let conn = match Connection::connect(connection_string, TlsMode::None) {
            Ok(conn) => conn,
            Err(err) => panic!("failed to connect using: {}, err: {}",
                               connection_string, err)
        };

        SiteDB {
            conn: Arc::new(Mutex::new(conn)),
        }
    }

    pub fn query_by_id(&self, uuid: &Uuid) -> Option<Query> {
        let rs = match self.conn.lock().as_mut().unwrap().query("SELECT query_json FROM query WHERE id = $1",
                                       &[uuid])
        {
            Ok(rs) => rs,
            Err(_) => return None,
        };

        if rs.len() > 0 {
            let query_value: Option<String> = rs.get(0).get(0);

            let query: Query = match serde_json::from_str(&query_value.unwrap()) {
                Ok(v) => v,
                Err(_) => return None,
            };

            return Some(query);
        }

        None
    }

    pub fn id_from_query(&self, query: &Query) -> Option<Uuid> {
        let query_value: String = match serde_json::value::to_value(query) {
            Ok(v) => v.to_string(),
            Err(err) => {
                eprint!("error converting query to string: {:?}\n", err);
                return None;
            }
        };

        let rs = match self.conn.lock().as_mut().unwrap().query("SELECT id::uuid FROM query WHERE digest(query_json, 'sha256') = digest($1, 'sha256');",
                                       &[&query_value])
        {
            Ok(rs) => rs,
            Err(err) => {
                eprint!("error querying in id_from_query(): {:?}\n", err);
                return None;
            }
        };

        if rs.len() > 0 {
            let id: Uuid = rs.get(0).get("id");
            Some(id)
        } else {
            None
        }
    }

    pub fn save_query(&self, uuid: &Uuid, query: &Query) -> Result<(), String> {
        let mut locked_conn = self.conn.lock();
        let trans = match locked_conn.as_mut().unwrap().transaction() {
            Ok(t) => t,
            Err(e) => return Err(format!("couldn't begin transaction: {}", e)),
        };

        let serde_value: String = match serde_json::value::to_value(&query) {
            Ok(v) => v.to_string(),
            Err(e) => return Err(format!("serde error: {}", e)),
        };

        match trans.execute("INSERT INTO query(id, query_json) values ($1, $2)",
                            &[uuid, &serde_value]) {
            Ok(_) => (),
            Err(e) => return Err(format!("Error executing query: {}", e)),
        };

        match trans.commit() {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{}", e)),
        }
    }
}
<|endoftext|>


<commit_before>use template::RdxSortTemplate;

impl RdxSortTemplate for u8 {
    fn cfg_nbuckets() -> usize {
        16
    }

    fn cfg_nrounds() -> usize {
        2
    }

    fn get_bucket(&self, round: usize) -> usize {
        let shift = round << 2;
        ((self >> shift) & 15u8) as usize
    }
}

impl RdxSortTemplate for u16 {
    fn cfg_nbuckets() -> usize {
        16
    }

    fn cfg_nrounds() -> usize {
        4
    }

    fn get_bucket(&self, round: usize) -> usize {
        let shift = round << 2;
        ((self >> shift) & 15u16) as usize
    }
}

impl RdxSortTemplate for u32 {
    fn cfg_nbuckets() -> usize {
        16
    }

    fn cfg_nrounds() -> usize {
        8
    }

    fn get_bucket(&self, round: usize) -> usize {
        let shift = round << 2;
        ((self >> shift) & 15u32) as usize
    }
}

impl RdxSortTemplate for u64 {
    fn cfg_nbuckets() -> usize {
        16
    }

    fn cfg_nrounds() -> usize {
        16
    }

    fn get_bucket(&self, round: usize) -> usize {
        let shift = round << 2;
        ((self >> shift) & 15u64) as usize
    }
}
<commit_msg>speed up u64 (and i64+f64)<commit_after>use template::RdxSortTemplate;

impl RdxSortTemplate for u8 {
    fn cfg_nbuckets() -> usize {
        16
    }

    fn cfg_nrounds() -> usize {
        2
    }

    fn get_bucket(&self, round: usize) -> usize {
        let shift = round << 2;
        ((self >> shift) & 15u8) as usize
    }
}

impl RdxSortTemplate for u16 {
    fn cfg_nbuckets() -> usize {
        16
    }

    fn cfg_nrounds() -> usize {
        4
    }

    fn get_bucket(&self, round: usize) -> usize {
        let shift = round << 2;
        ((self >> shift) & 15u16) as usize
    }
}

impl RdxSortTemplate for u32 {
    fn cfg_nbuckets() -> usize {
        16
    }

    fn cfg_nrounds() -> usize {
        8
    }

    fn get_bucket(&self, round: usize) -> usize {
        let shift = round << 2;
        ((self >> shift) & 15u32) as usize
    }
}

impl RdxSortTemplate for u64 {
    fn cfg_nbuckets() -> usize {
        64
    }

    fn cfg_nrounds() -> usize {
        11
    }

    fn get_bucket(&self, round: usize) -> usize {
        let shift = round * 6;
        ((self >> shift) & 31u64) as usize
    }
}
<|endoftext|>


<commit_before>use amq_protocol_types::*;
use format::field::*;
use format::frame::*;
use connection::*;
use generated::*;
use error::*;

#[derive(Clone,Debug,PartialEq,Eq)]
pub enum ChannelState {
  Initial,
  Connected,
  Closed,
  Error,
  SendingContent(usize),
  ReceivingContent(usize),
  {{#each specs.classes as |class| ~}}
  {{#unless class.is_connection}}
  {{#each class.methods as |method| ~}}{{#if method.synchronous }}Awaiting{{camel class.name}}{{camel method.name}}Ok,
  {{/if}}{{/each ~}}
  {{/unless}}
  {{/each ~}}
}

impl Connection {
  pub fn receive_method(&mut self, channel_id: u16, method: Class) -> Result<(), Error> {
    match method {
      {{#each specs.classes as |class| ~}}
      {{#unless class.is_connection}}
      {{#each class.methods as |method| ~}}
      Class::{{camel class.name}}({{snake class.name}}::Methods::{{camel method.name}}(m)) => {
        self.receive_{{snake class.name}}_{{snake method.name}}(channel_id, m)
      },
      {{/each ~}}
      {{/unless}}
      {{/each ~}}
    }
  }

  {{#each specs.classes as |class| ~}}
  {{#unless class.is_connection}}
  {{#each class.methods as |method| ~}}
  pub fn {{snake class.name}}_{{snake method.name}}(&mut self,
    _channel_id: u16{{#each method.arguments as |argument| ~}},
    {{snake argument.name}}: {{argument.type}}{{/each ~}}) -> Result<(), Error> {

      if !self.channels.contains_key(&_channel_id) {
        return Err(Error::InvalidChannel);
      }

      if ! self.channels.get_mut(&_channel_id).map(|c| c.state == ChannelState::Connected).unwrap_or(false) {
        return Err(Error::InvalidState);
      }

      let method = Class::{{camel class.name}}({{snake class.name}}::Methods::{{camel method.name}} (
        {{snake class.name}}::{{camel method.name}} {
          {{#each method.arguments as |argument| ~}}
          {{snake argument.name}}: {{snake argument.name}},
          {{/each ~}}
        }
      ));

      {{#if method.synchronous }}
      self.send_method_frame(_channel_id, &method).map(|_| {
        self.channels.get_mut(&_channel_id).map(|c| {
          c.state = ChannelState::Awaiting{{camel class.name}}{{camel method.name}}Ok;
          println!("channel {} state is now {:?}", _channel_id, c.state);
        });
      })
      {{else}}
      self.send_method_frame(_channel_id, &method)
      {{/if}}
  }

  pub fn receive_{{snake class.name}}_{{snake method.name}}(&mut self,
    _channel_id: u16, method: {{snake class.name}}::{{camel method.name}}) -> Result<(), Error> {

      if !self.channels.contains_key(&_channel_id) {
        println!("key {} not in channels {:?}", _channel_id, self.channels);
        return Err(Error::InvalidChannel);
      }

      match self.channels.get_mut(&_channel_id).map(|c| c.state.clone()).unwrap() {
        ChannelState::Initial | ChannelState::Connected => {},
        ChannelState::Error | ChannelState::Closed | ChannelState::SendingContent(_) | ChannelState::ReceivingContent(_) => {return Err(Error::InvalidState);},
        ChannelState::Awaiting{{camel class.name}}{{camel method.name}} => {
          self.channels.get_mut(&_channel_id).map(|c| c.state = ChannelState::Connected);
        }
        _ => {
          self.channels.get_mut(&_channel_id).map(|c| c.state = ChannelState::Error);
          return Err(Error::InvalidState);
        }
      }

      println!("unimplemented method {}.{}, ignoring packet", {{camel class.name}}, {{camel method.name}});

      Ok(())
  }
  {{/each ~}}
  {{/unless}}
{{/each ~}}
}

<commit_msg>fix debug log<commit_after>use amq_protocol_types::*;
use format::field::*;
use format::frame::*;
use connection::*;
use generated::*;
use error::*;

#[derive(Clone,Debug,PartialEq,Eq)]
pub enum ChannelState {
  Initial,
  Connected,
  Closed,
  Error,
  SendingContent(usize),
  ReceivingContent(usize),
  {{#each specs.classes as |class| ~}}
  {{#unless class.is_connection}}
  {{#each class.methods as |method| ~}}{{#if method.synchronous }}Awaiting{{camel class.name}}{{camel method.name}}Ok,
  {{/if}}{{/each ~}}
  {{/unless}}
  {{/each ~}}
}

impl Connection {
  pub fn receive_method(&mut self, channel_id: u16, method: Class) -> Result<(), Error> {
    match method {
      {{#each specs.classes as |class| ~}}
      {{#unless class.is_connection}}
      {{#each class.methods as |method| ~}}
      Class::{{camel class.name}}({{snake class.name}}::Methods::{{camel method.name}}(m)) => {
        self.receive_{{snake class.name}}_{{snake method.name}}(channel_id, m)
      },
      {{/each ~}}
      {{/unless}}
      {{/each ~}}
    }
  }

  {{#each specs.classes as |class| ~}}
  {{#unless class.is_connection}}
  {{#each class.methods as |method| ~}}
  pub fn {{snake class.name}}_{{snake method.name}}(&mut self,
    _channel_id: u16{{#each method.arguments as |argument| ~}},
    {{snake argument.name}}: {{argument.type}}{{/each ~}}) -> Result<(), Error> {

      if !self.channels.contains_key(&_channel_id) {
        return Err(Error::InvalidChannel);
      }

      if ! self.channels.get_mut(&_channel_id).map(|c| c.state == ChannelState::Connected).unwrap_or(false) {
        return Err(Error::InvalidState);
      }

      let method = Class::{{camel class.name}}({{snake class.name}}::Methods::{{camel method.name}} (
        {{snake class.name}}::{{camel method.name}} {
          {{#each method.arguments as |argument| ~}}
          {{snake argument.name}}: {{snake argument.name}},
          {{/each ~}}
        }
      ));

      {{#if method.synchronous }}
      self.send_method_frame(_channel_id, &method).map(|_| {
        self.channels.get_mut(&_channel_id).map(|c| {
          c.state = ChannelState::Awaiting{{camel class.name}}{{camel method.name}}Ok;
          println!("channel {} state is now {:?}", _channel_id, c.state);
        });
      })
      {{else}}
      self.send_method_frame(_channel_id, &method)
      {{/if}}
  }

  pub fn receive_{{snake class.name}}_{{snake method.name}}(&mut self,
    _channel_id: u16, method: {{snake class.name}}::{{camel method.name}}) -> Result<(), Error> {

      if !self.channels.contains_key(&_channel_id) {
        println!("key {} not in channels {:?}", _channel_id, self.channels);
        return Err(Error::InvalidChannel);
      }

      match self.channels.get_mut(&_channel_id).map(|c| c.state.clone()).unwrap() {
        ChannelState::Initial | ChannelState::Connected => {},
        ChannelState::Error | ChannelState::Closed | ChannelState::SendingContent(_) | ChannelState::ReceivingContent(_) => {return Err(Error::InvalidState);},
        ChannelState::Awaiting{{camel class.name}}{{camel method.name}} => {
          self.channels.get_mut(&_channel_id).map(|c| c.state = ChannelState::Connected);
        }
        _ => {
          self.channels.get_mut(&_channel_id).map(|c| c.state = ChannelState::Error);
          return Err(Error::InvalidState);
        }
      }

      println!("unimplemented method {{camel class.name}}.{{camel method.name}}, ignoring packet");

      Ok(())
  }
  {{/each ~}}
  {{/unless}}
{{/each ~}}
}

<|endoftext|>


<commit_before>use std::{
    path::{Path, PathBuf},
    process::Command,
};

use ra_syntax::SmolStr;
use ra_arena::{Arena, RawId, impl_arena_id};

use crate::Result;

#[derive(Debug, Clone)]
pub struct Sysroot {
    crates: Arena<SysrootCrate, SysrootCrateData>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SysrootCrate(RawId);
impl_arena_id!(SysrootCrate);

#[derive(Debug, Clone)]
struct SysrootCrateData {
    name: SmolStr,
    root: PathBuf,
    deps: Vec<SysrootCrate>,
}

impl Sysroot {
    pub(crate) fn std(&self) -> Option<SysrootCrate> {
        self.by_name("std")
    }

    pub(crate) fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + 'a {
        self.crates.iter().map(|(id, _data)| id)
    }

    pub(super) fn discover(cargo_toml: &Path) -> Result<Sysroot> {
        let rustc_output = Command::new("rustc")
            .current_dir(cargo_toml.parent().unwrap())
            .args(&["--print", "sysroot"])
            .output()?;
        if !rustc_output.status.success() {
            failure::bail!("failed to locate sysroot")
        }
        let stdout = String::from_utf8(rustc_output.stdout)?;
        let sysroot_path = Path::new(stdout.trim());
        let src = sysroot_path.join("lib/rustlib/src/rust/src");
        if !src.exists() {
            failure::bail!(
                "can't load standard library from sysroot\n\
                 {:?}\n\
                 try running `rustup component add rust-src`",
                src,
            );
        }

        let mut sysroot = Sysroot {
            crates: Arena::default(),
        };
        for name in SYSROOT_CRATES.trim().lines() {
            let root = src.join(format!("lib{}", name)).join("lib.rs");
            if root.exists() {
                sysroot.crates.alloc(SysrootCrateData {
                    name: name.into(),
                    root,
                    deps: Vec::new(),
                });
            }
        }
        if let Some(std) = sysroot.std() {
            for dep in STD_DEPS.trim().lines() {
                if let Some(dep) = sysroot.by_name(dep) {
                    sysroot.crates[std].deps.push(dep)
                }
            }
        }
        Ok(sysroot)
    }

    fn by_name(&self, name: &str) -> Option<SysrootCrate> {
        self.crates
            .iter()
            .find(|(_id, data)| data.name == name)
            .map(|(id, _data)| id)
    }
}

impl SysrootCrate {
    pub(crate) fn name(self, sysroot: &Sysroot) -> &SmolStr {
        &sysroot.crates[self].name
    }
    pub(crate) fn root(self, sysroot: &Sysroot) -> &Path {
        sysroot.crates[self].root.as_path()
    }
    pub(crate) fn root_dir(self, sysroot: &Sysroot) -> &Path {
        self.root(sysroot).parent().unwrap()
    }
    pub(crate) fn deps<'a>(self, sysroot: &'a Sysroot) -> impl Iterator<Item = SysrootCrate> + 'a {
        sysroot.crates[self].deps.iter().map(|&it| it)
    }
}

const SYSROOT_CRATES: &str = "
std
core
alloc
collections
libc
panic_unwind
proc_macro
rustc_unicode
std_unicode
test
alloc_jemalloc
alloc_system
compiler_builtins
getopts
panic_unwind
panic_abort
rand
term
unwind
build_helper
rustc_asan
rustc_lsan
rustc_msan
rustc_tsan
syntax";

const STD_DEPS: &str = "
alloc_jemalloc
alloc_system
panic_abort
rand
compiler_builtins
unwind
rustc_asan
rustc_lsan
rustc_msan
rustc_tsan
build_helper";
<commit_msg>Add core to STD_DEPS<commit_after>use std::{
    path::{Path, PathBuf},
    process::Command,
};

use ra_syntax::SmolStr;
use ra_arena::{Arena, RawId, impl_arena_id};

use crate::Result;

#[derive(Debug, Clone)]
pub struct Sysroot {
    crates: Arena<SysrootCrate, SysrootCrateData>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SysrootCrate(RawId);
impl_arena_id!(SysrootCrate);

#[derive(Debug, Clone)]
struct SysrootCrateData {
    name: SmolStr,
    root: PathBuf,
    deps: Vec<SysrootCrate>,
}

impl Sysroot {
    pub(crate) fn std(&self) -> Option<SysrootCrate> {
        self.by_name("std")
    }

    pub(crate) fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + 'a {
        self.crates.iter().map(|(id, _data)| id)
    }

    pub(super) fn discover(cargo_toml: &Path) -> Result<Sysroot> {
        let rustc_output = Command::new("rustc")
            .current_dir(cargo_toml.parent().unwrap())
            .args(&["--print", "sysroot"])
            .output()?;
        if !rustc_output.status.success() {
            failure::bail!("failed to locate sysroot")
        }
        let stdout = String::from_utf8(rustc_output.stdout)?;
        let sysroot_path = Path::new(stdout.trim());
        let src = sysroot_path.join("lib/rustlib/src/rust/src");
        if !src.exists() {
            failure::bail!(
                "can't load standard library from sysroot\n\
                 {:?}\n\
                 try running `rustup component add rust-src`",
                src,
            );
        }

        let mut sysroot = Sysroot {
            crates: Arena::default(),
        };
        for name in SYSROOT_CRATES.trim().lines() {
            let root = src.join(format!("lib{}", name)).join("lib.rs");
            if root.exists() {
                sysroot.crates.alloc(SysrootCrateData {
                    name: name.into(),
                    root,
                    deps: Vec::new(),
                });
            }
        }
        if let Some(std) = sysroot.std() {
            for dep in STD_DEPS.trim().lines() {
                if let Some(dep) = sysroot.by_name(dep) {
                    sysroot.crates[std].deps.push(dep)
                }
            }
        }
        Ok(sysroot)
    }

    fn by_name(&self, name: &str) -> Option<SysrootCrate> {
        self.crates
            .iter()
            .find(|(_id, data)| data.name == name)
            .map(|(id, _data)| id)
    }
}

impl SysrootCrate {
    pub(crate) fn name(self, sysroot: &Sysroot) -> &SmolStr {
        &sysroot.crates[self].name
    }
    pub(crate) fn root(self, sysroot: &Sysroot) -> &Path {
        sysroot.crates[self].root.as_path()
    }
    pub(crate) fn root_dir(self, sysroot: &Sysroot) -> &Path {
        self.root(sysroot).parent().unwrap()
    }
    pub(crate) fn deps<'a>(self, sysroot: &'a Sysroot) -> impl Iterator<Item = SysrootCrate> + 'a {
        sysroot.crates[self].deps.iter().map(|&it| it)
    }
}

const SYSROOT_CRATES: &str = "
std
core
alloc
collections
libc
panic_unwind
proc_macro
rustc_unicode
std_unicode
test
alloc_jemalloc
alloc_system
compiler_builtins
getopts
panic_unwind
panic_abort
rand
term
unwind
build_helper
rustc_asan
rustc_lsan
rustc_msan
rustc_tsan
syntax";

const STD_DEPS: &str = "
alloc_jemalloc
alloc_system
core
panic_abort
rand
compiler_builtins
unwind
rustc_asan
rustc_lsan
rustc_msan
rustc_tsan
build_helper";
<|endoftext|>