<commit_before>use std::{
    collections::HashMap,
    path::{Path, PathBuf},
};

use xshell::{cmd, read_file};
use xtask::{
    codegen::{self, Mode},
    project_root, run_rustfmt, rust_files,
};

#[test]
fn generated_grammar_is_fresh() {
    if let Err(error) = codegen::generate_syntax(Mode::Verify) {
        panic!("{}. Please update it by running `cargo xtask codegen`", error);
    }
}

#[test]
fn generated_tests_are_fresh() {
    if let Err(error) = codegen::generate_parser_tests(Mode::Verify) {
        panic!("{}. Please update tests by running `cargo xtask codegen`", error);
    }
}

#[test]
fn generated_assists_are_fresh() {
    if let Err(error) = codegen::generate_assists_tests(Mode::Verify) {
        panic!("{}. Please update assists by running `cargo xtask codegen`", error);
    }
}

#[test]
fn check_code_formatting() {
    if let Err(error) = run_rustfmt(Mode::Verify) {
        panic!("{}. Please format the code by running `cargo format`", error);
    }
}

#[test]
fn smoke_test_docs_generation() {
    // We don't commit docs to the repo, so we can just overwrite in tests.
    codegen::generate_assists_docs(Mode::Overwrite).unwrap();
    codegen::generate_feature_docs(Mode::Overwrite).unwrap();
    codegen::generate_diagnostic_docs(Mode::Overwrite).unwrap();
}

#[test]
fn check_lsp_extensions_docs() {
    let expected_hash = {
        let lsp_ext_rs =
            read_file(project_root().join("crates/rust-analyzer/src/lsp_ext.rs")).unwrap();
        stable_hash(lsp_ext_rs.as_str())
    };

    let actual_hash = {
        let lsp_extensions_md =
            read_file(project_root().join("docs/dev/lsp-extensions.md")).unwrap();
        let text = lsp_extensions_md
            .lines()
            .find_map(|line| line.strip_prefix("lsp_ext.rs hash:"))
            .unwrap()
            .trim();
        u64::from_str_radix(text, 16).unwrap()
    };

    if actual_hash != expected_hash {
        panic!(
            "
lsp_ext.rs was changed without touching lsp-extensions.md.

Expected hash: {:x}
Actual hash:   {:x}

Please adjust docs/dev/lsp-extensions.md.
",
            expected_hash, actual_hash
        )
    }
}

#[test]
fn rust_files_are_tidy() {
    let mut tidy_docs = TidyDocs::default();
    for path in rust_files(&project_root().join("crates")) {
        let text = read_file(&path).unwrap();
        check_todo(&path, &text);
        check_trailing_ws(&path, &text);
        deny_clippy(&path, &text);
        tidy_docs.visit(&path, &text);
    }
    tidy_docs.finish();
}

#[test]
fn check_merge_commits() {
    let stdout =
        dbg!(cmd!("git rev-list --merges --invert-grep --author 'bors\\[bot\\]' HEAD~19.."))
            .read()
            .unwrap();
    if !stdout.is_empty() {
        panic!(
            "
Merge commits are not allowed in the history.

When updating a pull-request, please rebase your feature branch
on top of master by running `git rebase master`. If rebase fails,
you can re-apply your changes like this:

  # Abort in-progress rebase, if any.
  $ git rebase --abort

  # Make the branch point to the latest commit from master,
  # while maintaining your local changes uncommited.
  $ git reset --soft origin/master

  # Commit all changes in a single batch.
  $ git commit -am'My changes'

  # Push the changes. We did a rebase, so we need `--force` option.
  # `--force-with-lease` is a more safe (Rusty) version of `--force`.
  $ git push --force-with-lease

And don't fear to mess something up during a rebase -- you can
always restore the previous state using `git ref-log`:

https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/#redo-after-undo-local
"
        );
    }
}

fn deny_clippy(path: &PathBuf, text: &String) {
    let ignore = &[
        // The documentation in string literals may contain anything for its own purposes
        "completion/src/generated_lint_completions.rs",
    ];
    if ignore.iter().any(|p| path.ends_with(p)) {
        return;
    }

    if text.contains("\u{61}llow(clippy") {
        panic!(
            "\n\nallowing lints is forbidden: {}.
rust-analyzer intentionally doesn't check clippy on CI.
You can allow lint globally via `xtask clippy`.
See https://github.com/rust-lang/rust-clippy/issues/5537 for discussion.

",
            path.display()
        )
    }
}

#[test]
fn check_licenses() {
    let expected = "
0BSD OR MIT OR Apache-2.0
Apache-2.0
Apache-2.0 OR BSL-1.0
Apache-2.0 OR MIT
Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
Apache-2.0/MIT
BSD-3-Clause
CC0-1.0
ISC
MIT
MIT / Apache-2.0
MIT OR Apache-2.0
MIT OR Apache-2.0 OR Zlib
MIT OR Zlib OR Apache-2.0
MIT/Apache-2.0
Unlicense OR MIT
Unlicense/MIT
Zlib OR Apache-2.0 OR MIT
"
    .lines()
    .filter(|it| !it.is_empty())
    .collect::<Vec<_>>();

    let meta = cmd!("cargo metadata --format-version 1").read().unwrap();
    let mut licenses = meta
        .split(|c| c == ',' || c == '{' || c == '}')
        .filter(|it| it.contains(r#""license""#))
        .map(|it| it.trim())
        .map(|it| it[r#""license":"#.len()..].trim_matches('"'))
        .collect::<Vec<_>>();
    licenses.sort();
    licenses.dedup();
    if licenses != expected {
        let mut diff = String::new();

        diff += &format!("New Licenses:\n");
        for &l in licenses.iter() {
            if !expected.contains(&l) {
                diff += &format!("  {}\n", l)
            }
        }

        diff += &format!("\nMissing Licenses:\n");
        for &l in expected.iter() {
            if !licenses.contains(&l) {
                diff += &format!("  {}\n", l)
            }
        }

        panic!("different set of licenses!\n{}", diff);
    }
    assert_eq!(licenses, expected);
}

fn check_todo(path: &Path, text: &str) {
    let need_todo = &[
        // This file itself obviously needs to use todo (<- like this!).
        "tests/cli.rs",
        // Some of our assists generate `todo!()`.
        "handlers/add_turbo_fish.rs",
        "handlers/generate_function.rs",
        // To support generating `todo!()` in assists, we have `expr_todo()` in
        // `ast::make`.
        "ast/make.rs",
        // The documentation in string literals may contain anything for its own purposes
        "completion/src/generated_lint_completions.rs",
    ];
    if need_todo.iter().any(|p| path.ends_with(p)) {
        return;
    }
    if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {
        // Generated by an assist
        if text.contains("${0:todo!()}") {
            return;
        }

        panic!(
            "\nTODO markers or todo! macros should not be committed to the master branch,\n\
             use FIXME instead\n\
             {}\n",
            path.display(),
        )
    }
}

fn check_trailing_ws(path: &Path, text: &str) {
    if is_exclude_dir(path, &["test_data"]) {
        return;
    }
    for (line_number, line) in text.lines().enumerate() {
        if line.chars().last().map(char::is_whitespace) == Some(true) {
            panic!("Trailing whitespace in {} at line {}", path.display(), line_number)
        }
    }
}

#[derive(Default)]
struct TidyDocs {
    missing_docs: Vec<String>,
    contains_fixme: Vec<PathBuf>,
}

impl TidyDocs {
    fn visit(&mut self, path: &Path, text: &str) {
        // Test hopefully don't really need comments, and for assists we already
        // have special comments which are source of doc tests and user docs.
        if is_exclude_dir(path, &["tests", "test_data"]) {
            return;
        }

        if is_exclude_file(path) {
            return;
        }

        let first_line = match text.lines().next() {
            Some(it) => it,
            None => return,
        };

        if first_line.starts_with("//!") {
            if first_line.contains("FIXME") {
                self.contains_fixme.push(path.to_path_buf());
            }
        } else {
            if text.contains("// Feature:") || text.contains("// Assist:") {
                return;
            }
            self.missing_docs.push(path.display().to_string());
        }

        fn is_exclude_file(d: &Path) -> bool {
            let file_names = ["tests.rs"];

            d.file_name()
                .unwrap_or_default()
                .to_str()
                .map(|f_n| file_names.iter().any(|name| *name == f_n))
                .unwrap_or(false)
        }
    }

    fn finish(self) {
        if !self.missing_docs.is_empty() {
            panic!(
                "\nMissing docs strings\n\n\
                 modules:\n{}\n\n",
                self.missing_docs.join("\n")
            )
        }

        let poorly_documented = [
            "hir",
            "hir_expand",
            "ide",
            "mbe",
            "parser",
            "profile",
            "project_model",
            "syntax",
            "tt",
            "hir_ty",
        ];

        let mut has_fixmes =
            poorly_documented.iter().map(|it| (*it, false)).collect::<HashMap<&str, bool>>();
        'outer: for path in self.contains_fixme {
            for krate in poorly_documented.iter() {
                if path.components().any(|it| it.as_os_str() == *krate) {
                    has_fixmes.insert(krate, true);
                    continue 'outer;
                }
            }
            panic!("FIXME doc in a fully-documented crate: {}", path.display())
        }

        for (krate, has_fixme) in has_fixmes.iter() {
            if !has_fixme {
                panic!("crate {} is fully documented :tada:, remove it from the list of poorly documented crates", krate)
            }
        }
    }
}

fn is_exclude_dir(p: &Path, dirs_to_exclude: &[&str]) -> bool {
    p.strip_prefix(project_root())
        .unwrap()
        .components()
        .rev()
        .skip(1)
        .filter_map(|it| it.as_os_str().to_str())
        .any(|it| dirs_to_exclude.contains(&it))
}

#[allow(deprecated)]
fn stable_hash(text: &str) -> u64 {
    use std::hash::{Hash, Hasher, SipHasher};

    let text = text.replace('\r', "");
    let mut hasher = SipHasher::default();
    text.hash(&mut hasher);
    hasher.finish()
}
<commit_msg>Extend git evacuation procedure<commit_after>use std::{
    collections::HashMap,
    path::{Path, PathBuf},
};

use xshell::{cmd, read_file};
use xtask::{
    codegen::{self, Mode},
    project_root, run_rustfmt, rust_files,
};

#[test]
fn generated_grammar_is_fresh() {
    if let Err(error) = codegen::generate_syntax(Mode::Verify) {
        panic!("{}. Please update it by running `cargo xtask codegen`", error);
    }
}

#[test]
fn generated_tests_are_fresh() {
    if let Err(error) = codegen::generate_parser_tests(Mode::Verify) {
        panic!("{}. Please update tests by running `cargo xtask codegen`", error);
    }
}

#[test]
fn generated_assists_are_fresh() {
    if let Err(error) = codegen::generate_assists_tests(Mode::Verify) {
        panic!("{}. Please update assists by running `cargo xtask codegen`", error);
    }
}

#[test]
fn check_code_formatting() {
    if let Err(error) = run_rustfmt(Mode::Verify) {
        panic!("{}. Please format the code by running `cargo format`", error);
    }
}

#[test]
fn smoke_test_docs_generation() {
    // We don't commit docs to the repo, so we can just overwrite in tests.
    codegen::generate_assists_docs(Mode::Overwrite).unwrap();
    codegen::generate_feature_docs(Mode::Overwrite).unwrap();
    codegen::generate_diagnostic_docs(Mode::Overwrite).unwrap();
}

#[test]
fn check_lsp_extensions_docs() {
    let expected_hash = {
        let lsp_ext_rs =
            read_file(project_root().join("crates/rust-analyzer/src/lsp_ext.rs")).unwrap();
        stable_hash(lsp_ext_rs.as_str())
    };

    let actual_hash = {
        let lsp_extensions_md =
            read_file(project_root().join("docs/dev/lsp-extensions.md")).unwrap();
        let text = lsp_extensions_md
            .lines()
            .find_map(|line| line.strip_prefix("lsp_ext.rs hash:"))
            .unwrap()
            .trim();
        u64::from_str_radix(text, 16).unwrap()
    };

    if actual_hash != expected_hash {
        panic!(
            "
lsp_ext.rs was changed without touching lsp-extensions.md.

Expected hash: {:x}
Actual hash:   {:x}

Please adjust docs/dev/lsp-extensions.md.
",
            expected_hash, actual_hash
        )
    }
}

#[test]
fn rust_files_are_tidy() {
    let mut tidy_docs = TidyDocs::default();
    for path in rust_files(&project_root().join("crates")) {
        let text = read_file(&path).unwrap();
        check_todo(&path, &text);
        check_trailing_ws(&path, &text);
        deny_clippy(&path, &text);
        tidy_docs.visit(&path, &text);
    }
    tidy_docs.finish();
}

#[test]
fn check_merge_commits() {
    let stdout =
        dbg!(cmd!("git rev-list --merges --invert-grep --author 'bors\\[bot\\]' HEAD~19.."))
            .read()
            .unwrap();
    if !stdout.is_empty() {
        panic!(
            "
Merge commits are not allowed in the history.

When updating a pull-request, please rebase your feature branch
on top of master by running `git rebase master`. If rebase fails,
you can re-apply your changes like this:

  # Just look around to see the current state.
  $ git status
  $ git log

  # Abort in-progress rebase and merges, if any.
  $ git rebase --abort
  $ git merge --abort

  # Make the branch point to the latest commit from master,
  # while maintaining your local changes uncommited.
  $ git reset --soft origin/master

  # Commit all changes in a single batch.
  $ git commit -am'My changes'

  # Verify that everything looks alright.
  $ git status
  $ git log

  # Push the changes. We did a rebase, so we need `--force` option.
  # `--force-with-lease` is a more safe (Rusty) version of `--force`.
  $ git push --force-with-lease

  # Verify that both local and remote branch point to the same commit.
  $ git log

And don't fear to mess something up during a rebase -- you can
always restore the previous state using `git ref-log`:

https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/#redo-after-undo-local
"
        );
    }
}

fn deny_clippy(path: &PathBuf, text: &String) {
    let ignore = &[
        // The documentation in string literals may contain anything for its own purposes
        "completion/src/generated_lint_completions.rs",
    ];
    if ignore.iter().any(|p| path.ends_with(p)) {
        return;
    }

    if text.contains("\u{61}llow(clippy") {
        panic!(
            "\n\nallowing lints is forbidden: {}.
rust-analyzer intentionally doesn't check clippy on CI.
You can allow lint globally via `xtask clippy`.
See https://github.com/rust-lang/rust-clippy/issues/5537 for discussion.

",
            path.display()
        )
    }
}

#[test]
fn check_licenses() {
    let expected = "
0BSD OR MIT OR Apache-2.0
Apache-2.0
Apache-2.0 OR BSL-1.0
Apache-2.0 OR MIT
Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
Apache-2.0/MIT
BSD-3-Clause
CC0-1.0
ISC
MIT
MIT / Apache-2.0
MIT OR Apache-2.0
MIT OR Apache-2.0 OR Zlib
MIT OR Zlib OR Apache-2.0
MIT/Apache-2.0
Unlicense OR MIT
Unlicense/MIT
Zlib OR Apache-2.0 OR MIT
"
    .lines()
    .filter(|it| !it.is_empty())
    .collect::<Vec<_>>();

    let meta = cmd!("cargo metadata --format-version 1").read().unwrap();
    let mut licenses = meta
        .split(|c| c == ',' || c == '{' || c == '}')
        .filter(|it| it.contains(r#""license""#))
        .map(|it| it.trim())
        .map(|it| it[r#""license":"#.len()..].trim_matches('"'))
        .collect::<Vec<_>>();
    licenses.sort();
    licenses.dedup();
    if licenses != expected {
        let mut diff = String::new();

        diff += &format!("New Licenses:\n");
        for &l in licenses.iter() {
            if !expected.contains(&l) {
                diff += &format!("  {}\n", l)
            }
        }

        diff += &format!("\nMissing Licenses:\n");
        for &l in expected.iter() {
            if !licenses.contains(&l) {
                diff += &format!("  {}\n", l)
            }
        }

        panic!("different set of licenses!\n{}", diff);
    }
    assert_eq!(licenses, expected);
}

fn check_todo(path: &Path, text: &str) {
    let need_todo = &[
        // This file itself obviously needs to use todo (<- like this!).
        "tests/cli.rs",
        // Some of our assists generate `todo!()`.
        "handlers/add_turbo_fish.rs",
        "handlers/generate_function.rs",
        // To support generating `todo!()` in assists, we have `expr_todo()` in
        // `ast::make`.
        "ast/make.rs",
        // The documentation in string literals may contain anything for its own purposes
        "completion/src/generated_lint_completions.rs",
    ];
    if need_todo.iter().any(|p| path.ends_with(p)) {
        return;
    }
    if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {
        // Generated by an assist
        if text.contains("${0:todo!()}") {
            return;
        }

        panic!(
            "\nTODO markers or todo! macros should not be committed to the master branch,\n\
             use FIXME instead\n\
             {}\n",
            path.display(),
        )
    }
}

fn check_trailing_ws(path: &Path, text: &str) {
    if is_exclude_dir(path, &["test_data"]) {
        return;
    }
    for (line_number, line) in text.lines().enumerate() {
        if line.chars().last().map(char::is_whitespace) == Some(true) {
            panic!("Trailing whitespace in {} at line {}", path.display(), line_number)
        }
    }
}

#[derive(Default)]
struct TidyDocs {
    missing_docs: Vec<String>,
    contains_fixme: Vec<PathBuf>,
}

impl TidyDocs {
    fn visit(&mut self, path: &Path, text: &str) {
        // Test hopefully don't really need comments, and for assists we already
        // have special comments which are source of doc tests and user docs.
        if is_exclude_dir(path, &["tests", "test_data"]) {
            return;
        }

        if is_exclude_file(path) {
            return;
        }

        let first_line = match text.lines().next() {
            Some(it) => it,
            None => return,
        };

        if first_line.starts_with("//!") {
            if first_line.contains("FIXME") {
                self.contains_fixme.push(path.to_path_buf());
            }
        } else {
            if text.contains("// Feature:") || text.contains("// Assist:") {
                return;
            }
            self.missing_docs.push(path.display().to_string());
        }

        fn is_exclude_file(d: &Path) -> bool {
            let file_names = ["tests.rs"];

            d.file_name()
                .unwrap_or_default()
                .to_str()
                .map(|f_n| file_names.iter().any(|name| *name == f_n))
                .unwrap_or(false)
        }
    }

    fn finish(self) {
        if !self.missing_docs.is_empty() {
            panic!(
                "\nMissing docs strings\n\n\
                 modules:\n{}\n\n",
                self.missing_docs.join("\n")
            )
        }

        let poorly_documented = [
            "hir",
            "hir_expand",
            "ide",
            "mbe",
            "parser",
            "profile",
            "project_model",
            "syntax",
            "tt",
            "hir_ty",
        ];

        let mut has_fixmes =
            poorly_documented.iter().map(|it| (*it, false)).collect::<HashMap<&str, bool>>();
        'outer: for path in self.contains_fixme {
            for krate in poorly_documented.iter() {
                if path.components().any(|it| it.as_os_str() == *krate) {
                    has_fixmes.insert(krate, true);
                    continue 'outer;
                }
            }
            panic!("FIXME doc in a fully-documented crate: {}", path.display())
        }

        for (krate, has_fixme) in has_fixmes.iter() {
            if !has_fixme {
                panic!("crate {} is fully documented :tada:, remove it from the list of poorly documented crates", krate)
            }
        }
    }
}

fn is_exclude_dir(p: &Path, dirs_to_exclude: &[&str]) -> bool {
    p.strip_prefix(project_root())
        .unwrap()
        .components()
        .rev()
        .skip(1)
        .filter_map(|it| it.as_os_str().to_str())
        .any(|it| dirs_to_exclude.contains(&it))
}

#[allow(deprecated)]
fn stable_hash(text: &str) -> u64 {
    use std::hash::{Hash, Hasher, SipHasher};

    let text = text.replace('\r', "");
    let mut hasher = SipHasher::default();
    text.hash(&mut hasher);
    hasher.finish()
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Example of enum definition<commit_after>fn main() {
    let four = IpAddrKind::V4;
    let six = IpAddrKind::V6;
}

enum IpAddrKind {
    V4,
    V6
}
<|endoftext|>


<commit_before>use std::iter::Iterator;
use std::result;
use std::collections::HashSet;

use token::Token;
use scanner::Scanner;

const EOL_CHAR: char = '\n';

lazy_static! {
    static ref SYMBOL_CHARS: HashSet<char> = vec![
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
        'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
        'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
        'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', '-', '_', '$', '^', '&', '*', '!', '@', '%', '+',
        '?', '<', '>', '.', ':', '/', '|', '~', ',', '='
    ].into_iter().collect();
}

#[derive(Debug, Eq, PartialEq)]
pub enum TokenError {
    UnrecognizedCharacter(char),
    UnexpectedEndOfInput,
    SymbolCannotBeNumber,
    ScannerError(String),
}

pub type TokenResult = result::Result<Token, TokenError>;

pub struct Tokenizer {
    scanner: Scanner,
    reached_eof: bool,
}

impl Tokenizer {
    pub fn new(scanner: Scanner) -> Tokenizer {
        Tokenizer {
            scanner: scanner,
            reached_eof: false,
        }
    }

    fn ignore_whitespace(&mut self) -> result::Result<(), &str> {
        loop {
            let c = self.scanner.get_char();
            if c.is_none() {
                break;
            }

            let c = c.unwrap();
            if !c.is_whitespace() || c == EOL_CHAR {
                try!(self.scanner.unget_char());
                break;
            }
        }

        Ok(())
    }

    fn next_symbol(&mut self, start: char) -> TokenResult {
        let mut symbol = String::new();

        let mut next_char = Some(start);
        while !next_char.is_none() {
            let c = next_char.unwrap();
            if SYMBOL_CHARS.contains(&c) {
                symbol.push(c)
            }
            else {
                try!(self.scanner.unget_char().map_err(|e| TokenError::ScannerError(e.to_owned())));
                break;
            }

            next_char = self.scanner.get_char();
        }

        if symbol.len() == 0 {
            Err(match self.scanner.get_char() {
                Some(c) => TokenError::UnrecognizedCharacter(c),
                None => TokenError::UnexpectedEndOfInput,
            })
        }
        else if symbol.chars().next().map_or(false, |c| c.is_digit(10)) {
            Err(TokenError::SymbolCannotBeNumber)
        }
        else if symbol == "=" {
            Ok(Token::Equals)
        }
        else {
            Ok(Token::Symbol(symbol))
        }
    }
}

impl Iterator for Tokenizer {
    type Item = TokenResult;

    fn next(&mut self) -> Option<Self::Item> {
        if self.reached_eof {
            return None;
        }

        if let Err(message) = self.ignore_whitespace() {
            return Some(Err(TokenError::ScannerError(message.to_owned())));
        }

        let c = self.scanner.get_char();
        if c.is_none() {
            self.reached_eof = true;
            return None;
        }

        let c = c.unwrap();
        Some(Ok(match c {
            '\\' => Token::Backslash,
            '(' => Token::ParenOpen,
            ')' => Token::ParenClose,
            '"' => Token::StringBoundary,
            EOL_CHAR => Token::EOL,
            _ => return Some(self.next_symbol(c)),
        }))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token::*;
    use scanner::Scanner;

    #[test]
    fn backslash() {
        let mut tokenizer = tokenizer_for("\\");
        assert_eq!(tokenizer.next().unwrap().unwrap(), Backslash);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn equals() {
        let mut tokenizer = tokenizer_for("=");
        assert_eq!(tokenizer.next().unwrap().unwrap(), Equals);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn paren_open() {
        let mut tokenizer = tokenizer_for("(");
        assert_eq!(tokenizer.next().unwrap().unwrap(), ParenOpen);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn paren_close() {
        let mut tokenizer = tokenizer_for(")");
        assert_eq!(tokenizer.next().unwrap().unwrap(), ParenClose);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn string_boundary() {
        let mut tokenizer = tokenizer_for("\"");
        assert_eq!(tokenizer.next().unwrap().unwrap(), StringBoundary);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn eol() {
        let mut tokenizer = tokenizer_for("\n");
        assert_eq!(tokenizer.next().unwrap().unwrap(), EOL);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn recognizes_multiple_tokens_separated_by_whitespace() {
        let mut tokenizer = tokenizer_for("\\ ) \n ( \\ = = )");
        let expected = [Backslash, ParenClose, EOL, ParenOpen, Backslash, Equals, Equals, ParenClose];

        for token in expected.into_iter() {
            assert_eq!(tokenizer.next().unwrap().unwrap(), *token);
        }

        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn groups_characters_into_symbols() {
        let symbol = "abqq$$1111^&/|!";
        let mut tokenizer = tokenizer_for(symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol.to_owned()));
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn groups_equals_into_symbols_when_there_is_no_whitespace() {
        let symbol = "=ifsaoi=hfsdMMDS,,,,~~~:=".to_owned();

        // Make sure leading whitespace does not effect the output
        let mut tokenizer = tokenizer_for(&format!("  {}", symbol));

        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol));
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn disallows_symbols_starting_with_numbers() {
        let symbol = "123abc~".to_owned();
        let mut tokenizer = tokenizer_for(&symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap_err(), TokenError::SymbolCannotBeNumber);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn disallows_invalid_characters() {
        let symbol = "]";
        let mut tokenizer = tokenizer_for(&symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap_err(), TokenError::UnrecognizedCharacter(']'));
        assert!(tokenizer.next().is_none());

        // Make sure invalid character is caught among valid characters too
        let symbol = "a12[$3abc~".to_owned();
        let mut tokenizer = tokenizer_for(&symbol);

        // Ignore first token
        assert!(tokenizer.next().unwrap().is_ok());
        assert_eq!(tokenizer.next().unwrap().unwrap_err(), TokenError::UnrecognizedCharacter('['));
        assert!(tokenizer.next().unwrap().is_ok());
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn accepts_all_valid_symbol_characters_into_a_symbol() {
        let symbol = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_$^&*!@%+?<>.:/|~,=".to_owned();
        let mut tokenizer = tokenizer_for(&symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol));
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn recognizes_parenthesis_regardless_of_whitespace() {
        let mut tokenizer = tokenizer_for("(x + y)())");
        let expected = [ParenOpen, Symbol("x".to_owned()), Symbol("+".to_owned()), Symbol("y".to_owned()), ParenClose, ParenOpen, ParenClose, ParenClose];

        for token in expected.into_iter() {
            assert_eq!(tokenizer.next().unwrap().unwrap(), *token);
        }

        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn recognizes_string_boundaries_regardless_of_whitespace() {
        let mut tokenizer = tokenizer_for("\"x + y\"\"\"\"");
        let expected = [StringBoundary, Symbol("x".to_owned()), Symbol("+".to_owned()), Symbol("y".to_owned()), StringBoundary, StringBoundary, StringBoundary, StringBoundary];

        for token in expected.into_iter() {
            assert_eq!(tokenizer.next().unwrap().unwrap(), *token);
        }

        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn ignores_leading_whitespace() {
        let symbol = "oh$*$ho".to_owned();
        let mut tokenizer = tokenizer_for(&format!("  \t\t  \t {}", symbol));
        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol.to_owned()));
        assert!(tokenizer.next().is_none());
    }

    fn tokenizer_for(string: &str) -> Tokenizer {
        Tokenizer::new(Scanner::from_str(string))
    }
}

<commit_msg>Refactoring next_symbol into two functions<commit_after>use std::iter::Iterator;
use std::result;
use std::collections::HashSet;

use token::Token;
use scanner::Scanner;

const EOL_CHAR: char = '\n';

lazy_static! {
    static ref SYMBOL_CHARS: HashSet<char> = vec![
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
        'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
        'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
        'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', '-', '_', '$', '^', '&', '*', '!', '@', '%', '+',
        '?', '<', '>', '.', ':', '/', '|', '~', ',', '='
    ].into_iter().collect();
}

#[derive(Debug, Eq, PartialEq)]
pub enum TokenError {
    UnrecognizedCharacter(char),
    UnexpectedEndOfInput,
    SymbolCannotBeNumber,
    ScannerError(String),
}

pub type TokenResult = result::Result<Token, TokenError>;

pub struct Tokenizer {
    scanner: Scanner,
    reached_eof: bool,
}

impl Tokenizer {
    pub fn new(scanner: Scanner) -> Tokenizer {
        Tokenizer {
            scanner: scanner,
            reached_eof: false,
        }
    }

    fn ignore_whitespace(&mut self) -> result::Result<(), &str> {
        loop {
            let c = self.scanner.get_char();
            if c.is_none() {
                break;
            }

            let c = c.unwrap();
            if !c.is_whitespace() || c == EOL_CHAR {
                try!(self.scanner.unget_char());
                break;
            }
        }

        Ok(())
    }

    fn next_symbol(&mut self, start: char) -> TokenResult {
        let mut symbol = String::new();

        let mut next_char = Some(start);
        while !next_char.is_none() {
            let c = next_char.unwrap();
            if SYMBOL_CHARS.contains(&c) {
                symbol.push(c)
            }
            else {
                try!(self.scanner.unget_char()
                    .map_err(|e| TokenError::ScannerError(e.to_owned())));
                break;
            }

            next_char = self.scanner.get_char();
        }

        self.validate_symbol(symbol)
    }

    fn validate_symbol(&mut self, symbol: String) -> TokenResult {
        if symbol.len() == 0 {
            Err(match self.scanner.get_char() {
                Some(c) => TokenError::UnrecognizedCharacter(c),
                None => TokenError::UnexpectedEndOfInput,
            })
        }
        else if symbol.chars().next().map_or(false, |c| c.is_digit(10)) {
            Err(TokenError::SymbolCannotBeNumber)
        }
        else if symbol == "=" {
            Ok(Token::Equals)
        }
        else {
            Ok(Token::Symbol(symbol))
        }
    }
}

impl Iterator for Tokenizer {
    type Item = TokenResult;

    fn next(&mut self) -> Option<Self::Item> {
        if self.reached_eof {
            return None;
        }

        if let Err(message) = self.ignore_whitespace() {
            return Some(Err(TokenError::ScannerError(message.to_owned())));
        }

        let c = self.scanner.get_char();
        if c.is_none() {
            self.reached_eof = true;
            return None;
        }

        let c = c.unwrap();
        Some(Ok(match c {
            '\\' => Token::Backslash,
            '(' => Token::ParenOpen,
            ')' => Token::ParenClose,
            '"' => Token::StringBoundary,
            EOL_CHAR => Token::EOL,
            _ => return Some(self.next_symbol(c)),
        }))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::Token::*;
    use scanner::Scanner;

    #[test]
    fn backslash() {
        let mut tokenizer = tokenizer_for("\\");
        assert_eq!(tokenizer.next().unwrap().unwrap(), Backslash);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn equals() {
        let mut tokenizer = tokenizer_for("=");
        assert_eq!(tokenizer.next().unwrap().unwrap(), Equals);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn paren_open() {
        let mut tokenizer = tokenizer_for("(");
        assert_eq!(tokenizer.next().unwrap().unwrap(), ParenOpen);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn paren_close() {
        let mut tokenizer = tokenizer_for(")");
        assert_eq!(tokenizer.next().unwrap().unwrap(), ParenClose);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn string_boundary() {
        let mut tokenizer = tokenizer_for("\"");
        assert_eq!(tokenizer.next().unwrap().unwrap(), StringBoundary);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn eol() {
        let mut tokenizer = tokenizer_for("\n");
        assert_eq!(tokenizer.next().unwrap().unwrap(), EOL);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn recognizes_multiple_tokens_separated_by_whitespace() {
        let mut tokenizer = tokenizer_for("\\ ) \n ( \\ = = )");
        let expected = [Backslash, ParenClose, EOL, ParenOpen, Backslash, Equals, Equals, ParenClose];

        for token in expected.into_iter() {
            assert_eq!(tokenizer.next().unwrap().unwrap(), *token);
        }

        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn groups_characters_into_symbols() {
        let symbol = "abqq$$1111^&/|!";
        let mut tokenizer = tokenizer_for(symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol.to_owned()));
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn groups_equals_into_symbols_when_there_is_no_whitespace() {
        let symbol = "=ifsaoi=hfsdMMDS,,,,~~~:=".to_owned();

        // Make sure leading whitespace does not effect the output
        let mut tokenizer = tokenizer_for(&format!("  {}", symbol));

        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol));
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn disallows_symbols_starting_with_numbers() {
        let symbol = "123abc~".to_owned();
        let mut tokenizer = tokenizer_for(&symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap_err(), TokenError::SymbolCannotBeNumber);
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn disallows_invalid_characters() {
        let symbol = "]";
        let mut tokenizer = tokenizer_for(&symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap_err(), TokenError::UnrecognizedCharacter(']'));
        assert!(tokenizer.next().is_none());

        // Make sure invalid character is caught among valid characters too
        let symbol = "a12[$3abc~".to_owned();
        let mut tokenizer = tokenizer_for(&symbol);

        // Ignore first token
        assert!(tokenizer.next().unwrap().is_ok());
        assert_eq!(tokenizer.next().unwrap().unwrap_err(), TokenError::UnrecognizedCharacter('['));
        assert!(tokenizer.next().unwrap().is_ok());
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn accepts_all_valid_symbol_characters_into_a_symbol() {
        let symbol = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_$^&*!@%+?<>.:/|~,=".to_owned();
        let mut tokenizer = tokenizer_for(&symbol);
        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol));
        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn recognizes_parenthesis_regardless_of_whitespace() {
        let mut tokenizer = tokenizer_for("(x + y)())");
        let expected = [ParenOpen, Symbol("x".to_owned()), Symbol("+".to_owned()), Symbol("y".to_owned()), ParenClose, ParenOpen, ParenClose, ParenClose];

        for token in expected.into_iter() {
            assert_eq!(tokenizer.next().unwrap().unwrap(), *token);
        }

        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn recognizes_string_boundaries_regardless_of_whitespace() {
        let mut tokenizer = tokenizer_for("\"x + y\"\"\"\"");
        let expected = [StringBoundary, Symbol("x".to_owned()), Symbol("+".to_owned()), Symbol("y".to_owned()), StringBoundary, StringBoundary, StringBoundary, StringBoundary];

        for token in expected.into_iter() {
            assert_eq!(tokenizer.next().unwrap().unwrap(), *token);
        }

        assert!(tokenizer.next().is_none());
    }

    #[test]
    fn ignores_leading_whitespace() {
        let symbol = "oh$*$ho".to_owned();
        let mut tokenizer = tokenizer_for(&format!("  \t\t  \t {}", symbol));
        assert_eq!(tokenizer.next().unwrap().unwrap(), Symbol(symbol.to_owned()));
        assert!(tokenizer.next().is_none());
    }

    fn tokenizer_for(string: &str) -> Tokenizer {
        Tokenizer::new(Scanner::from_str(string))
    }
}

<|endoftext|>


<commit_before>extern crate vec3;

use num::Num;
use length::length_values;

#[inline(always)]
pub fn transform_angle<T: Num>(out: &mut [T; 2], a: [T; 2], angle: T) -> &mut [T; 2] {
    let c = angle.cos();
    let s = angle.sin();

    out[0] = a[0] * c - a[1] * s;
    out[1] = a[0] * s + a[1] * c;
    out
}

#[inline(always)]
pub fn transform_mat2<T: Num>(out: &mut [T; 2], a: [T; 2], m: [T; 4]) -> &mut [T; 2] {
    out[0] = a[0] * m[0] + a[1] * m[2];
    out[1] = a[0] * m[1] + a[1] * m[3];
    out
}

#[inline(always)]
pub fn transform_mat32<T: Num>(out: &mut [T; 2], a: [T; 2], m: [T; 6]) -> &mut [T; 2] {
    out[0] = a[0] * m[0] + a[1] * m[2] + m[4];
    out[1] = a[0] * m[1] + a[1] * m[3] + m[5];
    out
}

#[inline(always)]
pub fn transform_mat3<T: Num>(out: &mut [T; 2], a: [T; 2], m: [T; 9]) -> &mut [T; 2] {
    out[0] = a[0] * m[0] + a[1] * m[3] + m[6];
    out[1] = a[0] * m[1] + a[1] * m[4] + m[7];
    out
}

#[inline(always)]
pub fn transform_mat4<T: Num>(out: &mut [T; 2], a: [T; 2], m: [T; 16]) -> &mut [T; 2] {
    out[0] = a[0] * m[0] + a[1] * m[4] + m[12];
    out[1] = a[0] * m[1] + a[1] * m[5] + m[13];
    out
}

#[inline(always)]
pub fn transform_projection<T: Num>(out: &mut [T; 2], a: [T; 2], m: [T; 16]) -> &mut [T; 2] {
    let mut d = a[0] * m[3] + a[1] * m[7] + m[11] + m[15];
    d = if d != T::zero() {T::one() / d} else {d};

    out[0] = (a[0] * m[0] + a[1] * m[4] + m[12]) * d;
    out[1] = (a[0] * m[1] + a[1] * m[5] + m[13]) * d;
    out
}

#[inline(always)]
pub fn position_mat32<T: Num>(out: &mut [T; 2], m: [T; 6]) -> &mut [T; 2] {
    out[0] = m[4];
    out[1] = m[5];
    out
}

#[inline(always)]
pub fn position_mat4<T: Num>(out: &mut [T; 2], m: [T; 16]) -> &mut [T; 2] {
    out[0] = m[12];
    out[1] = m[13];
    out
}

#[inline(always)]
pub fn scale_mat2<T: Num>(out: &mut [T; 2], m: [T; 4]) -> &mut [T; 2] {
    out[0] = length_values(m[0], m[2]);
    out[1] = length_values(m[1], m[3]);
    out
}

#[inline(always)]
pub fn scale_mat32<T: Num>(out: &mut [T; 2], m: [T; 6]) -> &mut [T; 2] {
    out[0] = length_values(m[0], m[2]);
    out[1] = length_values(m[1], m[3]);
    out
}

#[inline(always)]
pub fn scale_mat3<T: Num>(out: &mut [T; 2], m: [T; 9]) -> &mut [T; 2] {
    out[0] = vec3::length_values(m[0], m[3], m[6]);
    out[1] = vec3::length_values(m[1], m[4], m[7]);
    out
}

#[inline(always)]
pub fn scale_mat4<T: Num>(out: &mut [T; 2], m: [T; 16]) -> &mut [T; 2] {
    out[0] = vec3::length_values(m[0], m[4], m[8]);
    out[1] = vec3::length_values(m[1], m[5], m[9]);
    out
}
<commit_msg>updates<commit_after>extern crate vec3;

use num::Num;
use length::length_values;

#[inline(always)]
pub fn transform_angle<T: Num>(out: &mut [T; 2], a: [T; 2], angle: T) -> &mut [T; 2] {
    let c = angle.cos();
    let s = angle.sin();

    out[0] = a[0] * c - a[1] * s;
    out[1] = a[0] * s + a[1] * c;
    out
}

#[inline(always)]
pub fn transform_mat2<T: Num>(out: &mut [T; 2], a: [T; 2], m: [T; 4]) -> &mut [T; 2] {
    out[0] = a[0] * m[0] + a[1] * m[2];
    out[1] = a[0] * m[1] + a[1] * m[3];
    out
}

#[inline(always)]
pub fn transform_mat32<T: Num>(out: &mut [T; 2], a: [T; 2], m: [T; 6]) -> &mut [T; 2] {
    out[0] = a[0] * m[0] + a[1] * m[2] + m[4];
    out[1] = a[0] * m[1] + a[1] * m[3] + m[5];
    out
}

#[inline(always)]
pub fn transform_mat3<T: Num>(out: &mut [T; 2], a: [T; 2], m: [T; 9]) -> &mut [T; 2] {
    out[0] = a[0] * m[0] + a[1] * m[3] + m[6];
    out[1] = a[0] * m[1] + a[1] * m[4] + m[7];
    out
}

#[inline(always)]
pub fn transform_mat4<T: Num>(out: &mut [T; 2], a: [T; 2], m: [T; 16]) -> &mut [T; 2] {
    out[0] = a[0] * m[0] + a[1] * m[4] + m[12];
    out[1] = a[0] * m[1] + a[1] * m[5] + m[13];
    out
}

#[inline(always)]
pub fn transform_projection<T: Num>(out: &mut [T; 2], a: [T; 2], m: [T; 16]) -> &mut [T; 2] {
    let mut d = a[0] * m[3] + a[1] * m[7] + m[11] + m[15];
    d = if d != T::zero() {T::one() / d} else {d};

    out[0] = (a[0] * m[0] + a[1] * m[4] + a[2] * m[8] + m[12]) * d;
    out[1] = (a[0] * m[1] + a[1] * m[5] + a[2] * m[9] + m[13]) * d;
    out
}

#[inline(always)]
pub fn transform_projection_no_position<T: Num>(out: &mut [T; 2], a: [T; 2], m: [T; 16]) -> &mut [T; 2] {
    let mut d = a[0] * m[3] + a[1] * m[7] + m[11] + m[15];
    d = if d != T::zero() {T::one() / d} else {d};

    out[0] = (a[0] * m[0] + a[1] * m[4] + a[2] * m[8]) * d;
    out[1] = (a[0] * m[1] + a[1] * m[5] + a[2] * m[9]) * d;
    out
}

#[inline(always)]
pub fn position_mat32<T: Num>(out: &mut [T; 2], m: [T; 6]) -> &mut [T; 2] {
    out[0] = m[4];
    out[1] = m[5];
    out
}

#[inline(always)]
pub fn position_mat4<T: Num>(out: &mut [T; 2], m: [T; 16]) -> &mut [T; 2] {
    out[0] = m[12];
    out[1] = m[13];
    out
}

#[inline(always)]
pub fn scale_mat2<T: Num>(out: &mut [T; 2], m: [T; 4]) -> &mut [T; 2] {
    out[0] = length_values(m[0], m[2]);
    out[1] = length_values(m[1], m[3]);
    out
}

#[inline(always)]
pub fn scale_mat32<T: Num>(out: &mut [T; 2], m: [T; 6]) -> &mut [T; 2] {
    out[0] = length_values(m[0], m[2]);
    out[1] = length_values(m[1], m[3]);
    out
}

#[inline(always)]
pub fn scale_mat3<T: Num>(out: &mut [T; 2], m: [T; 9]) -> &mut [T; 2] {
    out[0] = vec3::length_values(m[0], m[3], m[6]);
    out[1] = vec3::length_values(m[1], m[4], m[7]);
    out
}

#[inline(always)]
pub fn scale_mat4<T: Num>(out: &mut [T; 2], m: [T; 16]) -> &mut [T; 2] {
    out[0] = vec3::length_values(m[0], m[4], m[8]);
    out[1] = vec3::length_values(m[1], m[5], m[9]);
    out
}
<|endoftext|>


<commit_before>/*
 * PCG Random Number Generation for Rust
 *
 * Copyright 2015 John Brooks <robojeb@robojeb.xyz>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * This work is derived from the implementation PCG RNG for C++ by
 * Melissa O'Neill.
 *
 * For additional information about the PCG random number generation scheme,
 * including its license and other licensing options, visit
 *
 *     http://www.pcg-random.org
 */

use num_traits::{PrimInt, ToPrimitive};
use ::numops::*;
use std::ops::{Shr, BitXor};

/// The output mixin trait provides the permutation function for the output
/// of the PCG. After the LCG state is advanced the state is run through
/// the `output(...)` function to produce the output.
pub trait OutputMixin<Itype, Xtype> {
    fn output(state : Itype) -> Xtype;
}

/// This output uses an Xor-shift followed by a right shift
pub struct XshRsMixin;

impl<Itype, Xtype> OutputMixin<Itype, Xtype> for XshRsMixin
    where
    Itype: Shr<usize, Output=Itype> + BitXor<Itype, Output=Itype> + AsSmaller<Xtype> + BitSize + ToPrimitive + Copy,
    Xtype: BitSize {

    #[inline(always)]
    fn output(state : Itype) -> Xtype {
        let mut state = state;
        let sparebits = Itype::bits() - Xtype::bits();

        let opbits : usize = if sparebits - 5 >= 64 { 5 } else
                        if sparebits - 4 >= 32 { 4 } else
                        if sparebits - 3 >= 16 { 3 } else
                        if sparebits - 2 >= 4  { 2 } else
                        if sparebits - 1 >= 1  { 1 } else { 0 };
        let mask = (1 << opbits) -1;
        let maxrandshift = mask;
        let topspare = opbits;
        let bottomspare = sparebits - topspare;
        let xshift = topspare + (Xtype::bits()+maxrandshift)/2;

        let rshift = if opbits != 0 {
            (state >> (Itype::bits() - opbits)).to_usize().unwrap() & mask
        } else {
            0
        };

        state = state ^ (state >> xshift);
        (state >> (bottomspare - maxrandshift + rshift)).shrink()
    }
}

/// This output uses an xor-shift followed by a random rotation.
pub struct XshRrMixin;

impl<Itype, Xtype> OutputMixin<Itype, Xtype> for XshRrMixin
    where Itype: Shr<usize, Output=Itype> + BitXor<Itype, Output=Itype> + ToPrimitive + AsSmaller<Xtype> + BitSize + Copy,
    Xtype: BitSize + PrimInt {

    #[inline(always)]
    fn output(state : Itype) -> Xtype {
        let mut state = state;

        let sparebits = Itype::bits() - Xtype::bits();
        let xtypebits = Xtype::bits();
        let wantedopbits : usize = if xtypebits >= 128 { 7 } else
                            if xtypebits >= 64 { 6 } else
                            if xtypebits >= 32 { 5 } else
                            if xtypebits >= 16 { 4 } else { 3 };

        let opbits : usize = if sparebits >= wantedopbits {
            wantedopbits
        } else {
            sparebits
        };

        let amplifier = wantedopbits - opbits;
        let mask = (1 << opbits) - 1;
        let topspare = opbits;
        let bottomspare = sparebits - topspare;
        let xshift = (topspare + xtypebits)/2;

        let rot = if opbits != 0 {
            (state >> (Itype::bits() - opbits)).to_usize().unwrap() & mask
        } else { 0 };

        let amprot = (rot << amplifier) & mask;
        state = state ^ (state >> xshift);

        let result : Xtype = (state >> bottomspare).shrink();
        result.rotate_right(amprot as u32)
    }
}
<commit_msg>changed to non-checked usize<commit_after>/*
 * PCG Random Number Generation for Rust
 *
 * Copyright 2015 John Brooks <robojeb@robojeb.xyz>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * This work is derived from the implementation PCG RNG for C++ by
 * Melissa O'Neill.
 *
 * For additional information about the PCG random number generation scheme,
 * including its license and other licensing options, visit
 *
 *     http://www.pcg-random.org
 */

use num_traits::{PrimInt};
use ::numops::*;
use std::ops::{Shr, BitXor};

/// The output mixin trait provides the permutation function for the output
/// of the PCG. After the LCG state is advanced the state is run through
/// the `output(...)` function to produce the output.
pub trait OutputMixin<Itype, Xtype> {
    fn output(state : Itype) -> Xtype;
}

/// This output uses an Xor-shift followed by a right shift
pub struct XshRsMixin;

impl<Itype, Xtype> OutputMixin<Itype, Xtype> for XshRsMixin
    where
    Itype: Shr<usize, Output=Itype> + BitXor<Itype, Output=Itype> + AsSmaller<Xtype> + BitSize + AsUsize + Copy,
    Xtype: BitSize {

    #[inline(always)]
    fn output(state : Itype) -> Xtype {
        let mut state = state;
        let sparebits = Itype::bits() - Xtype::bits();

        let opbits : usize = if sparebits - 5 >= 64 { 5 } else
                        if sparebits - 4 >= 32 { 4 } else
                        if sparebits - 3 >= 16 { 3 } else
                        if sparebits - 2 >= 4  { 2 } else
                        if sparebits - 1 >= 1  { 1 } else { 0 };
        let mask = (1 << opbits) -1;
        let maxrandshift = mask;
        let topspare = opbits;
        let bottomspare = sparebits - topspare;
        let xshift = topspare + (Xtype::bits()+maxrandshift)/2;

        let rshift = if opbits != 0 {
            (state >> (Itype::bits() - opbits)).as_usize() & mask
        } else {
            0
        };

        state = state ^ (state >> xshift);
        (state >> (bottomspare - maxrandshift + rshift)).shrink()
    }
}

/// This output uses an xor-shift followed by a random rotation.
pub struct XshRrMixin;

impl<Itype, Xtype> OutputMixin<Itype, Xtype> for XshRrMixin
    where Itype: Shr<usize, Output=Itype> + BitXor<Itype, Output=Itype> + AsUsize + AsSmaller<Xtype> + BitSize + Copy,
    Xtype: BitSize + PrimInt {

    #[inline(always)]
    fn output(state : Itype) -> Xtype {
        let mut state = state;

        let sparebits = Itype::bits() - Xtype::bits();
        let xtypebits = Xtype::bits();
        let wantedopbits : usize = if xtypebits >= 128 { 7 } else
                            if xtypebits >= 64 { 6 } else
                            if xtypebits >= 32 { 5 } else
                            if xtypebits >= 16 { 4 } else { 3 };

        let opbits : usize = if sparebits >= wantedopbits {
            wantedopbits
        } else {
            sparebits
        };

        let amplifier = wantedopbits - opbits;
        let mask = (1 << opbits) - 1;
        let topspare = opbits;
        let bottomspare = sparebits - topspare;
        let xshift = (topspare + xtypebits)/2;

        let rot = if opbits != 0 {
            (state >> (Itype::bits() - opbits)).as_usize() & mask
        } else { 0 };

        let amprot = (rot << amplifier) & mask;
        state = state ^ (state >> xshift);

        let result : Xtype = (state >> bottomspare).shrink();
        result.rotate_right(amprot as u32)
    }
}
<|endoftext|>


<commit_before>//! Example of a global thread-local loggers
//!
//! This somewhat of an anti-pattern, as loggers should be
//! context(data)-aware and trying to not pass them around is going against
//! the approach.
//!
//! `Logger`-s should be embedded in the objects so they can be accessed as
//! `self.log.info!(....)` - this way there's no need to pass as function
//! arguments.
//!
//! If the there's a need to log something about thread-context, a closure
//! should be used to return a thread-local value.  See
//! `example/thread-local-closure.rs`.
#[macro_use]
extern crate slog;

use std::cell::RefCell;
use std::thread;

use slog::Logger;

thread_local!(static TL_LOG: RefCell<Logger> = RefCell::new(
    Logger::root(slog::Discard, o!("logger" => "unititalized"))
));

fn foo() {
    TL_LOG.with(|log| {
        info!(log.borrow(), "foo called");
    });
}

fn main() {
    let root = slog::Logger::root(
        slog::Discard,
        o!("version" => "0.0.1", "build-id" => "8dfljdf"),
        );

    TL_LOG.with(|log| {
        *log.borrow_mut() = root.new(o!("thread-id" => "main"));
    });

    let mut join = vec![];

    for i in 0..4 {
        join.push(thread::spawn({
            let root = root.clone();
            move || {

                TL_LOG.with(|log| {
                    *log.borrow_mut() = root.new(o!("thread-id" => format!("thread{}", i)));
                });

                foo();
            }
        }));
    }

    foo();

    for join in join {
        join.join().unwrap();
    }
}
<commit_msg>Fix typo ("unititalized" => "uninitialized")<commit_after>//! Example of a global thread-local loggers
//!
//! This somewhat of an anti-pattern, as loggers should be
//! context(data)-aware and trying to not pass them around is going against
//! the approach.
//!
//! `Logger`-s should be embedded in the objects so they can be accessed as
//! `self.log.info!(....)` - this way there's no need to pass as function
//! arguments.
//!
//! If the there's a need to log something about thread-context, a closure
//! should be used to return a thread-local value.  See
//! `example/thread-local-closure.rs`.
#[macro_use]
extern crate slog;

use std::cell::RefCell;
use std::thread;

use slog::Logger;

thread_local!(static TL_LOG: RefCell<Logger> = RefCell::new(
    Logger::root(slog::Discard, o!("logger" => "uninitialized"))
));

fn foo() {
    TL_LOG.with(|log| {
        info!(log.borrow(), "foo called");
    });
}

fn main() {
    let root = slog::Logger::root(
        slog::Discard,
        o!("version" => "0.0.1", "build-id" => "8dfljdf"),
        );

    TL_LOG.with(|log| {
        *log.borrow_mut() = root.new(o!("thread-id" => "main"));
    });

    let mut join = vec![];

    for i in 0..4 {
        join.push(thread::spawn({
            let root = root.clone();
            move || {

                TL_LOG.with(|log| {
                    *log.borrow_mut() = root.new(o!("thread-id" => format!("thread{}", i)));
                });

                foo();
            }
        }));
    }

    foo();

    for join in join {
        join.join().unwrap();
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Entry;

fn lowercase(word: &str) -> String {
    let mut lower = String::with_capacity(word.len());
    for c in word.chars() {
        for low in c.to_lowercase() {
            lower.push(low);
        }
    }
    lower
}

pub fn word_count(input: &str) -> HashMap<String, u32> {
    let mut map: HashMap<String, u32> = HashMap::new();
    let lower = lowercase(input);
    let slice: &str = lower.as_ref();
    for word in slice.split(|c: char| !c.is_alphanumeric()).filter(|s| !s.is_empty()) {
        match map.entry(word.to_string()) {
            Entry::Vacant(entry) => { entry.insert(1); },
            Entry::Occupied(mut entry) => {
                *entry.get_mut() += 1;
            }
        };
    }
    map
}
<commit_msg>word-count: use `str#to_lowercase`<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Entry;

pub fn word_count(input: &str) -> HashMap<String, u32> {
    let mut map: HashMap<String, u32> = HashMap::new();
    let lower = input.to_lowercase();
    let slice: &str = lower.as_ref();
    for word in slice.split(|c: char| !c.is_alphanumeric()).filter(|s| !s.is_empty()) {
        match map.entry(word.to_string()) {
            Entry::Vacant(entry) => { entry.insert(1); },
            Entry::Occupied(mut entry) => {
                *entry.get_mut() += 1;
            }
        };
    }
    map
}
<|endoftext|>


<commit_before>//! Definition of the triangle shape.

use std::mem;
use na::{self, Point3, Unit};
use na::Real;
use shape::{BaseMeshElement, SupportMap};
use math::{Isometry, Point};
use utils;

/// A triangle shape.
#[derive(PartialEq, Debug, Clone)]
pub struct Triangle<P> {
    a: P,
    b: P,
    c: P,
}

/// Description of the location of a point on a triangle.
#[derive(Copy, Clone, Debug)]
pub enum TrianglePointLocation<N: Real> {
    /// The point lies on a vertex.
    OnVertex(usize),
    /// The point lies on an edge.
    OnEdge(usize, [N; 2]),
    /// The point lies on the triangle interior.
    OnFace([N; 3]),
    /// The point lies on the triangle interior (for "solid" point queries).
    OnSolid,
}

impl<N: Real> TrianglePointLocation<N> {
    /// Returns `true` if the point is located on the relative interior of the triangle.
    pub fn is_on_face(&self) -> bool {
        if let TrianglePointLocation::OnFace(_) = *self {
            true
        } else {
            false
        }
    }
}

impl<P: Point> Triangle<P> {
    /// Creates a triangle from three points.
    #[inline]
    pub fn new(a: P, b: P, c: P) -> Triangle<P> {
        assert!(na::dimension::<P::Vector>() > 1);
        Triangle { a, b, c }
    }

    /// Creates the reference to a triangle from the reference to an array of three points.
    pub fn from_array(arr: &[P; 3]) -> &Triangle<P> {
        unsafe { mem::transmute(arr) }
    }

    pub(crate) fn from_array4(arr: &[P; 4]) -> &Triangle<P> {
        unsafe { mem::transmute(arr) }
    }

    /// The fist point of this triangle.
    #[inline]
    pub fn a(&self) -> &P {
        &self.a
    }

    /// The second point of this triangle.
    #[inline]
    pub fn b(&self) -> &P {
        &self.b
    }

    /// The third point of this triangle.
    #[inline]
    pub fn c(&self) -> &P {
        &self.c
    }

    /// The normal of this triangle assuming it is oriented ccw.
    ///
    /// The normal points such that it is collinear to `AB × AC` (where `×` denotes the cross
    /// product).
    #[inline]
    pub fn normal(&self) -> Unit<P::Vector> {
        Unit::new_normalize(self.scaled_normal())
    }

    /// A vector normal of this triangle.
    ///
    /// The vector points such that it is collinear to `AB × AC` (where `×` denotes the cross
    /// product).
    #[inline]
    pub fn scaled_normal(&self) -> P::Vector {
        let ab = self.b - self.a;
        let ac = self.c - self.a;
        utils::cross3(&ab, &ac)
    }
}

impl<P: Point> BaseMeshElement<Point3<usize>, P> for Triangle<P> {
    #[inline]
    fn new_with_vertices_and_indices(vs: &[P], is: &Point3<usize>) -> Triangle<P> {
        Triangle::new(vs[is.x], vs[is.y], vs[is.z])
    }
}

impl<P: Point, M: Isometry<P>> SupportMap<P, M> for Triangle<P> {
    #[inline]
    fn support_point(&self, m: &M, dir: &P::Vector) -> P {
        let local_dir = m.inverse_rotate_vector(dir);

        let d1 = na::dot(&self.a().coordinates(), &local_dir);
        let d2 = na::dot(&self.b().coordinates(), &local_dir);
        let d3 = na::dot(&self.c().coordinates(), &local_dir);

        let res = if d1 > d2 {
            if d1 > d3 {
                self.a()
            } else {
                self.c()
            }
        } else {
            if d2 > d3 {
                self.b()
            } else {
                self.c()
            }
        };

        m.transform_point(res)
    }
}
<commit_msg>WIP: implement ConvexPolyhedron for Triangle.<commit_after>//! Definition of the triangle shape.

use std::mem;
use approx::ApproxEq;
use na::{self, Point3, Unit};
use na::Real;
use shape::{BaseMeshElement, SupportMap};
use math::{Isometry, Point};
use utils;

/// A triangle shape.
#[derive(PartialEq, Debug, Clone)]
pub struct Triangle<P> {
    a: P,
    b: P,
    c: P,
}

/// Description of the location of a point on a triangle.
#[derive(Copy, Clone, Debug)]
pub enum TrianglePointLocation<N: Real> {
    /// The point lies on a vertex.
    OnVertex(usize),
    /// The point lies on an edge.
    OnEdge(usize, [N; 2]),
    /// The point lies on the triangle interior.
    OnFace([N; 3]),
    /// The point lies on the triangle interior (for "solid" point queries).
    OnSolid,
}

impl<N: Real> TrianglePointLocation<N> {
    /// Returns `true` if the point is located on the relative interior of the triangle.
    pub fn is_on_face(&self) -> bool {
        if let TrianglePointLocation::OnFace(_) = *self {
            true
        } else {
            false
        }
    }
}

impl<P: Point> Triangle<P> {
    /// Creates a triangle from three points.
    #[inline]
    pub fn new(a: P, b: P, c: P) -> Triangle<P> {
        assert!(na::dimension::<P::Vector>() > 1);
        Triangle { a, b, c }
    }

    /// Creates the reference to a triangle from the reference to an array of three points.
    pub fn from_array(arr: &[P; 3]) -> &Triangle<P> {
        unsafe { mem::transmute(arr) }
    }

    pub(crate) fn from_array4(arr: &[P; 4]) -> &Triangle<P> {
        unsafe { mem::transmute(arr) }
    }

    /// The fist point of this triangle.
    #[inline]
    pub fn a(&self) -> &P {
        &self.a
    }

    /// The second point of this triangle.
    #[inline]
    pub fn b(&self) -> &P {
        &self.b
    }

    /// The third point of this triangle.
    #[inline]
    pub fn c(&self) -> &P {
        &self.c
    }

    /// The normal of this triangle assuming it is oriented ccw.
    ///
    /// The normal points such that it is collinear to `AB × AC` (where `×` denotes the cross
    /// product).
    #[inline]
    pub fn normal(&self) -> Option<Unit<P::Vector>> {
        Unit::try_new(self.scaled_normal(), P::Real::default_epsilon())
    }

    /// A vector normal of this triangle.
    ///
    /// The vector points such that it is collinear to `AB × AC` (where `×` denotes the cross
    /// product).
    #[inline]
    pub fn scaled_normal(&self) -> P::Vector {
        let ab = self.b - self.a;
        let ac = self.c - self.a;
        utils::cross3(&ab, &ac)
    }
}

impl<P: Point> BaseMeshElement<Point3<usize>, P> for Triangle<P> {
    #[inline]
    fn new_with_vertices_and_indices(vs: &[P], is: &Point3<usize>) -> Triangle<P> {
        Triangle::new(vs[is.x], vs[is.y], vs[is.z])
    }
}

impl<P: Point, M: Isometry<P>> SupportMap<P, M> for Triangle<P> {
    #[inline]
    fn support_point(&self, m: &M, dir: &P::Vector) -> P {
        let local_dir = m.inverse_rotate_vector(dir);

        let d1 = na::dot(&self.a().coordinates(), &local_dir);
        let d2 = na::dot(&self.b().coordinates(), &local_dir);
        let d3 = na::dot(&self.c().coordinates(), &local_dir);

        let res = if d1 > d2 {
            if d1 > d3 {
                self.a()
            } else {
                self.c()
            }
        } else {
            if d2 > d3 {
                self.b()
            } else {
                self.c()
            }
        };

        m.transform_point(res)
    }
}

// impl<P: Point, M: Isometry<P>> ConvexPolyhedron<P, M> for Triangle<P> {
//     fn vertex(&self, id: FeatureId) -> P {
//         match id.unwrap_vertex() {
//             0 => self.a,
//             1 => self.b,
//             2 => self.c,
//             _ => panic!("Triangle vertex index out of bounds."),
//         }
//     }
//     fn edge(&self, id: FeatureId) -> (P, P, FeatureId, FeatureId) {
//         match id.unwrap_edge() {
//             0 => (self.a, self.b, FeatureId::Vertex(0), FeatureId::Vertex(1)),
//             2 => (self.b, self.c, FeatureId::Vertex(1), FeatureId::Vertex(2)),
//             3 => (self.c, self.a, FeatureId::Vertex(2), FeatureId::Vertex(0)),
//             _ => panic!("Triangle edge index out of bounds."),
//         }
//     }

//     fn face(&self, id: FeatureId, face: &mut ConvexPolyface<P>) {
//         if na::dimension::<P::Vector>() != 2 {
//             panic!("A segment does not have any face indimensions higher than 2.")
//         }

//         face.clear();

//         if let Some(normal) = self.normal() {
//             face.set_feature_id(id);

//             match id.unwrap_face() {
//                 0 => {
//                     face.push(self.a, FeatureId::Vertex(0));
//                     face.push(self.b, FeatureId::Vertex(1));
//                     face.push(self.c, FeatureId::Vertex(2));
//                     face.set_normal(normal);
//                 }
//                 1 => {
//                     face.push(self.a, FeatureId::Vertex(0));
//                     face.push(self.c, FeatureId::Vertex(2));
//                     face.push(self.b, FeatureId::Vertex(1));
//                     face.set_normal(-normal);
//                 }
//                 _ => unreachable!(),
//             }
//         } else {
//             face.push(self.a, FeatureId::Vertex(0));
//             face.set_feature_id(FeatureId::Vertex(0));
//         }
//     }

//     fn normal_cone(&self, feature: FeatureId) -> PolyhedralCone<P::Vector> {
//         if let Some(direction) = self.direction() {
//             match feature {
//                 FeatureId::Vertex(id) => {
//                     if id == 0 {
//                         PolyhedralCone::HalfSpace(direction)
//                     } else {
//                         PolyhedralCone::HalfSpace(-direction)
//                     }
//                 }
//                 FeatureId::Edge(_) => PolyhedralCone::OrthogonalSubspace(direction),
//                 FeatureId::Face(id) => {
//                     assert!(na::dimension::<P::Vector>() == 2);

//                     let mut dir = P::Vector::zero();
//                     if id == 0 {
//                         dir[0] = direction[1];
//                         dir[1] = -direction[0];
//                     } else {
//                         dir[0] = -direction[1];
//                         dir[1] = direction[0];
//                     }
//                     PolyhedralCone::HalfLine(Unit::new_unchecked(dir))
//                 }
//                 _ => PolyhedralCone::Empty,
//             }
//         } else {
//             PolyhedralCone::Full
//         }
//     }

//     fn support_face_toward(&self, m: &M, dir: &Unit<P::Vector>, face: &mut ConvexPolyface<P>) {
//         assert!(na::dimension::<P::Vector>() == 3);
//         let normal = self.scaled_normal();

//         if na::dot(&normal, &*dir) >= na::zero() {
//             ConvexPolyhedron::<P, M>::face(self, FeatureId::Face(0), face);
//         } else {
//             ConvexPolyhedron::<P, M>::face(self, FeatureId::Face(1), face);
//         }
//         face.transform_by(m)
//     }

//     fn support_feature_toward(
//         &self,
//         transform: &M,
//         dir: &Unit<P::Vector>,
//         _angle: P::Real,
//         out: &mut ConvexPolyface<P>,
//     ) {
//         out.clear();
//         // FIXME: actualy find the support feature.
//         self.support_face_toward(transform, dir, out)
//     }

//     fn support_feature_id_toward(&self, local_dir: &Unit<P::Vector>) -> FeatureId {
//         if let Some(normal) = self.normal() {
//             let eps: P::Real = na::convert(f64::consts::PI / 180.0);
//             let (seps, ceps) = eps.sin_cos();

//             let normal_dot = na::dot(&*local_dir, &*normal);
//             if normal_dot >= ceps {
//                 FeatureId::Face(0)
//             } else if normal_dot <= -ceps {
//                 FeatureId::Face(1)
//             }
//         } else {
//             unimplemented!()
//         }
//     }
// }
<|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!
    while true {
        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;
}

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

    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);
        } 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);
            } 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
                );
            };
        } else {
            result = format!(
                "{} is (proven) composite (failed sprp test base {}).",
                n, 17
            );
        };
    };

    return result;
}

#[wasm_bindgen]
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 != "".to_owned() {
            list = list + &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 body = document.body().expect("document should have a body");

    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));
    ()
}

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 body = document.body().expect("document should have a body");

    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 => "", 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 => "1", At::MaxLength => "2"}
                    ],
                    " prime numbers after ",
                    input![
                        attrs! {At::Type => "number", At::Size => "19", At::Id => "start", At::Value => "0", 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);
    }
}
<commit_msg>List fixed. check() now returns true/false and result.<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!
    while true {
        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 mut 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 body = document.body().expect("document should have a body");

    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 body = document.body().expect("document should have a body");

    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 => "", 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 => "1", At::MaxLength => "2"}
                    ],
                    " prime numbers after ",
                    input![
                        attrs! {At::Type => "number", At::Size => "19", At::Id => "start", At::Value => "0", 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);
    }
}
<|endoftext|>