<commit_before>//! This is the wasm web-gui.
//! This file is only compiled for the wasm32 target.

#![cfg(target_arch = "wasm32")]
#![recursion_limit = "512"]

mod application;
mod dictionary;
mod game;
mod image;
mod secret;

use crate::application::Application;
use crate::application::HangmanBackend;
use crate::application::{AUTHOR, CONF_TEMPLATE, TITLE, VERSION};
use crate::game::State;
use wasm_bindgen::prelude::*;
use yew::events::KeyboardEvent;
use yew::prelude::*;
use yew::services::reader::{File, FileData, ReaderService, ReaderTask};
use yew::services::{ConsoleService, DialogService};
use yew::{html, Component, ComponentLink, Html, InputData, ShouldRender};

#[derive(Debug)]
pub enum Scene {
    Playground(Application),
    ConfigureGame,
    GameOver,
}

pub struct GuiState {
    config_text: String,
    guess: String,
}

pub struct Model {
    link: ComponentLink<Self>,
    reader: ReaderService,
    console: ConsoleService,
    filereader_tasks: Vec<ReaderTask>,
    dialog: DialogService,
    scene: Scene,
    state: GuiState,
}

#[derive(Debug)]
pub enum Msg {
    SwitchTo(Scene),
    ConfigTextDelete,
    ConfigTextUpdate(String),
    ConfigReady,
    Files(Vec<File>),
    Loaded(FileData),
    UpdateGuess(String),
    Guess,
    Nope,
    NextRound,
}

impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
        let state = GuiState {
            config_text: String::from(CONF_TEMPLATE),
            guess: String::new(),
        };

        Model {
            link,
            reader: ReaderService::new(),
            console: ConsoleService::new(),
            filereader_tasks: vec![],
            dialog: DialogService::new(),
            scene: Scene::ConfigureGame,
            state,
        }
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        let mut new_scene = None;
        match &mut self.scene {
            Scene::Playground(ref mut app) => match msg {
                Msg::SwitchTo(Scene::ConfigureGame) => {
                    new_scene = Some(Scene::ConfigureGame);
                }
                Msg::SwitchTo(Scene::GameOver) => {
                    new_scene = Some(Scene::GameOver);
                }
                Msg::UpdateGuess(val) => {
                    self.state.guess = val.chars().rev().take(1).collect();
                    self.console.debug(&self.state.guess);
                }
                Msg::Guess => {
                    app.process_user_input(&self.state.guess);
                    self.state.guess = String::new();
                }
                Msg::Nope => {}
                unexpected => {
                    panic!(
                        "Unexpected message when configurations list shown: {:?}",
                        unexpected
                    );
                }
            },
            Scene::ConfigureGame => match msg {
                Msg::ConfigTextUpdate(val) => {
                    self.state.config_text = val;
                }
                Msg::ConfigTextDelete => {
                    self.state.config_text.clear();
                }
                Msg::SwitchTo(Scene::Playground(app)) => {
                    new_scene = Some(Scene::Playground(app));
                }

                Msg::SwitchTo(Scene::GameOver) => {
                    if self.dialog.confirm("Do you really want to quit this game?") {
                        new_scene = Some(Scene::GameOver);
                    }
                }

                Msg::Loaded(file) => {
                    if let Ok(s) = std::str::from_utf8(&file.content) {
                        self.state.config_text.push_str(s);
                    } else {
                        self.dialog
                            .alert(&format!("Can not read text file: {}", file.name));
                    }
                }
                Msg::Files(files) => {
                    for file in files.into_iter() {
                        let task = {
                            let callback = self.link.callback(Msg::Loaded);
                            self.reader.read_file(file, callback).unwrap()
                        };
                        self.filereader_tasks.push(task);
                    }
                }
                Msg::ConfigReady => {
                    match Application::new(self.state.config_text.as_str()) {
                        Ok(app) => {
                            self.link
                                .send_message(Msg::SwitchTo(Scene::Playground(app)));
                        }
                        Err(e) => self
                            .dialog
                            .alert(&format!("Can not parse configuration:\n {}", e)),
                    };
                }
                unexpected => {
                    panic!(
                        "Unexpected message during new config editing: {:?}",
                        unexpected
                    );
                }
            },
            Scene::GameOver => match msg {
                Msg::SwitchTo(Scene::ConfigureGame) => {
                    new_scene = Some(Scene::ConfigureGame);
                }
                unexpected => {
                    panic!("Unexpected message for settings scene: {:?}", unexpected);
                }
            },
        }
        if let Some(new_scene) = new_scene.take() {
            self.scene = new_scene;
        }
        true
    }

    fn change(&mut self, _: Self::Properties) -> ShouldRender {
        false
    }

    fn view(&self) -> Html {
        let header = move || -> Html {
            html! {
 {TITLE}
 }
        };
        let footer = move || -> Html {
            html! {
             {"User Manual"}
            {", "}  {"Desktop Version"}
            {", "}  {"Documentation"}
            {", "}  {"Source Code"}
            {", Version "} {VERSION.unwrap()} {", "} {AUTHOR}   }
        };
        match self.scene {
            Scene::ConfigureGame => html! { <>
                {header()}

 {"Enter your secrets here:"}

                    <textarea class=("conf-text")
                        placeholder=CONF_TEMPLATE
                        cols=80
                        rows=25
                        value=&self.state.config_text
                        oninput=self.link.callback(|e: InputData| Msg::ConfigTextUpdate(e.value)) />

 { "or load secrets from files: "}
                        <input type="file" multiple=true onchange=self.link.callback(move |value| {
                                let mut result = Vec::new();
                                if let ChangeData::Files(files) = value {
                                    let files = js_sys::try_iter(&files)
                                        .unwrap()
                                        .unwrap()
                                        .into_iter()
                                        .map(|v| File::from(v.unwrap()));
                                    result.extend(files);
                                }
                                Msg::Files(result)
                            })/>

                    <button disabled=self.state.config_text.is_empty()
                            onclick=self.link.callback(|_| Msg::ConfigTextDelete)>{ "Delete Secrets" }</button>
                    <button disabled=self.state.config_text.is_empty()
                            onclick=self.link.callback(|_| Msg::ConfigReady)>{ "Start Game" }</button>

                {footer()}
                </>
            },
            Scene::Playground(ref app) => {
                let secret = app.render_secret();
                let (cols, rows) = dimensions(&secret);
                let secret = secret.trim_end_matches("\n");
                let image = app.render_image();
                let image = image.trim_end_matches("\n");
                html! { <>
                    {header()}

                            <textarea class=("image")
                                placeholder="Image"
                                cols=format!("{}", &app.get_image_dimension().0)
                                rows=format!("{}", &app.get_image_dimension().1)
                                value=image
                                readonly=true
                            />

                            { app.render_game_lifes() } { " " }

                            { app.render_game_last_guess() }

                            <textarea class=("secret")
                                cols=cols+1
                                rows=rows
                                value=secret
                                readonly=true
                            />

                            { app.render_instructions() }
                            <input class="guess"
                                type="text"
                                autofocus=true
                                size=1
                                value=self.state.guess
                                oninput=self.link.callback(|e: InputData| Msg::UpdateGuess(e.value))
                                onkeypress=self.link.callback(|e: KeyboardEvent| {
                                   if e.key() == "Enter" { Msg::Guess } else { Msg::Nope }
                                }) />

                        <button disabled={app.get_state() == State::Ongoing || app.get_state() == State::VictoryGameOver}
                                onclick=self.link.callback(|_| Msg::Guess)>{ "Continue Game" }</button>
                        <button disabled={app.get_state() != State::VictoryGameOver}
                                onclick=self.link.callback(|_| Msg::SwitchTo(Scene::ConfigureGame))>{ "Reset Game" }</button>
                        <button disabled={app.get_state() != State::VictoryGameOver}
                                onclick=self.link.callback(|_| Msg::SwitchTo(Scene::GameOver))>{ "End Game" }</button>

                    </>
                }
            }
            Scene::GameOver => html! { <>
                {header()}

 { "Bye bye!" }

                    <button onclick=self.link.callback(|_| Msg::SwitchTo(Scene::ConfigureGame))>{ "No, Continue Playing" }</button>

                {footer()}
                </>
            },
        }
    }
}

/// Returns the columns and lines of the smallest
/// grid that can display this multi-line string `s`.
pub fn dimensions(s: &str) -> (usize, usize) {
    let mut row = 0;
    let mut col = 0;
    for l in s.lines() {
        let c = l.chars().count();
        if c > col {
            col = c;
        };
        row += 1;
    }
    (col, row)
}

#[wasm_bindgen(start)]
pub fn run_app() {
    App::<Model>::new().mount_to_body();
}

#[cfg(test)]
mod tests {
    use super::*;
    use secret::Secret;
    #[test]
    fn test_dimensions() {
        let secret = Secret::new("Lorem ipsum dolor sit amet, consectetur adipiscing\
         elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\
         quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure\
         dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\
         sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est\
         laborum.");

        //secret.disclose_all();

        assert_eq!(dimensions(format!("{}", secret).as_str()), (68, 22));
        //assert_eq!(format!("{}", secret), String::new());
    }
}
<commit_msg>add footer to playground scene<commit_after>//! This is the wasm web-gui.
//! This file is only compiled for the wasm32 target.

#![cfg(target_arch = "wasm32")]
#![recursion_limit = "512"]

mod application;
mod dictionary;
mod game;
mod image;
mod secret;

use crate::application::Application;
use crate::application::HangmanBackend;
use crate::application::{AUTHOR, CONF_TEMPLATE, TITLE, VERSION};
use crate::game::State;
use wasm_bindgen::prelude::*;
use yew::events::KeyboardEvent;
use yew::prelude::*;
use yew::services::reader::{File, FileData, ReaderService, ReaderTask};
use yew::services::{ConsoleService, DialogService};
use yew::{html, Component, ComponentLink, Html, InputData, ShouldRender};

#[derive(Debug)]
pub enum Scene {
    Playground(Application),
    ConfigureGame,
    GameOver,
}

pub struct GuiState {
    config_text: String,
    guess: String,
}

pub struct Model {
    link: ComponentLink<Self>,
    reader: ReaderService,
    console: ConsoleService,
    filereader_tasks: Vec<ReaderTask>,
    dialog: DialogService,
    scene: Scene,
    state: GuiState,
}

#[derive(Debug)]
pub enum Msg {
    SwitchTo(Scene),
    ConfigTextDelete,
    ConfigTextUpdate(String),
    ConfigReady,
    Files(Vec<File>),
    Loaded(FileData),
    UpdateGuess(String),
    Guess,
    Nope,
    NextRound,
}

impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
        let state = GuiState {
            config_text: String::from(CONF_TEMPLATE),
            guess: String::new(),
        };

        Model {
            link,
            reader: ReaderService::new(),
            console: ConsoleService::new(),
            filereader_tasks: vec![],
            dialog: DialogService::new(),
            scene: Scene::ConfigureGame,
            state,
        }
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        let mut new_scene = None;
        match &mut self.scene {
            Scene::Playground(ref mut app) => match msg {
                Msg::SwitchTo(Scene::ConfigureGame) => {
                    new_scene = Some(Scene::ConfigureGame);
                }
                Msg::SwitchTo(Scene::GameOver) => {
                    new_scene = Some(Scene::GameOver);
                }
                Msg::UpdateGuess(val) => {
                    self.state.guess = val.chars().rev().take(1).collect();
                    self.console.debug(&self.state.guess);
                }
                Msg::Guess => {
                    app.process_user_input(&self.state.guess);
                    self.state.guess = String::new();
                }
                Msg::Nope => {}
                unexpected => {
                    panic!(
                        "Unexpected message when configurations list shown: {:?}",
                        unexpected
                    );
                }
            },
            Scene::ConfigureGame => match msg {
                Msg::ConfigTextUpdate(val) => {
                    self.state.config_text = val;
                }
                Msg::ConfigTextDelete => {
                    self.state.config_text.clear();
                }
                Msg::SwitchTo(Scene::Playground(app)) => {
                    new_scene = Some(Scene::Playground(app));
                }

                Msg::SwitchTo(Scene::GameOver) => {
                    if self.dialog.confirm("Do you really want to quit this game?") {
                        new_scene = Some(Scene::GameOver);
                    }
                }

                Msg::Loaded(file) => {
                    if let Ok(s) = std::str::from_utf8(&file.content) {
                        self.state.config_text.push_str(s);
                    } else {
                        self.dialog
                            .alert(&format!("Can not read text file: {}", file.name));
                    }
                }
                Msg::Files(files) => {
                    for file in files.into_iter() {
                        let task = {
                            let callback = self.link.callback(Msg::Loaded);
                            self.reader.read_file(file, callback).unwrap()
                        };
                        self.filereader_tasks.push(task);
                    }
                }
                Msg::ConfigReady => {
                    match Application::new(self.state.config_text.as_str()) {
                        Ok(app) => {
                            self.link
                                .send_message(Msg::SwitchTo(Scene::Playground(app)));
                        }
                        Err(e) => self
                            .dialog
                            .alert(&format!("Can not parse configuration:\n {}", e)),
                    };
                }
                unexpected => {
                    panic!(
                        "Unexpected message during new config editing: {:?}",
                        unexpected
                    );
                }
            },
            Scene::GameOver => match msg {
                Msg::SwitchTo(Scene::ConfigureGame) => {
                    new_scene = Some(Scene::ConfigureGame);
                }
                unexpected => {
                    panic!("Unexpected message for settings scene: {:?}", unexpected);
                }
            },
        }
        if let Some(new_scene) = new_scene.take() {
            self.scene = new_scene;
        }
        true
    }

    fn change(&mut self, _: Self::Properties) -> ShouldRender {
        false
    }

    fn view(&self) -> Html {
        let header = move || -> Html {
            html! {
 {TITLE}
 }
        };
        let footer = move || -> Html {
            html! {
             {"User Manual"}
            {", "}  {"Desktop Version"}
            {", "}  {"Documentation"}
            {", "}  {"Source Code"}
            {", Version "} {VERSION.unwrap()} {", "} {AUTHOR}   }
        };
        match self.scene {
            Scene::ConfigureGame => html! { <>
                {header()}

 {"Enter your secrets here:"}

                    <textarea class=("conf-text")
                        placeholder=CONF_TEMPLATE
                        cols=80
                        rows=25
                        value=&self.state.config_text
                        oninput=self.link.callback(|e: InputData| Msg::ConfigTextUpdate(e.value)) />

 { "or load secrets from files: "}
                        <input type="file" multiple=true onchange=self.link.callback(move |value| {
                                let mut result = Vec::new();
                                if let ChangeData::Files(files) = value {
                                    let files = js_sys::try_iter(&files)
                                        .unwrap()
                                        .unwrap()
                                        .into_iter()
                                        .map(|v| File::from(v.unwrap()));
                                    result.extend(files);
                                }
                                Msg::Files(result)
                            })/>

                    <button disabled=self.state.config_text.is_empty()
                            onclick=self.link.callback(|_| Msg::ConfigTextDelete)>{ "Delete Secrets" }</button>
                    <button disabled=self.state.config_text.is_empty()
                            onclick=self.link.callback(|_| Msg::ConfigReady)>{ "Start Game" }</button>

                {footer()}
                </>
            },
            Scene::Playground(ref app) => {
                let secret = app.render_secret();
                let (cols, rows) = dimensions(&secret);
                let secret = secret.trim_end_matches("\n");
                let image = app.render_image();
                let image = image.trim_end_matches("\n");
                html! { <>
                    {header()}

                            <textarea class=("image")
                                placeholder="Image"
                                cols=format!("{}", &app.get_image_dimension().0)
                                rows=format!("{}", &app.get_image_dimension().1)
                                value=image
                                readonly=true
                            />

                            { app.render_game_lifes() } { " " }

                            { app.render_game_last_guess() }

                            <textarea class=("secret")
                                cols=cols+1
                                rows=rows
                                value=secret
                                readonly=true
                            />

                            { app.render_instructions() }
                            <input class="guess"
                                type="text"
                                autofocus=true
                                size=1
                                value=self.state.guess
                                oninput=self.link.callback(|e: InputData| Msg::UpdateGuess(e.value))
                                onkeypress=self.link.callback(|e: KeyboardEvent| {
                                   if e.key() == "Enter" { Msg::Guess } else { Msg::Nope }
                                }) />

                        <button disabled={app.get_state() == State::Ongoing || app.get_state() == State::VictoryGameOver}
                                onclick=self.link.callback(|_| Msg::Guess)>{ "Continue Game" }</button>
                        <button disabled={app.get_state() != State::VictoryGameOver}
                                onclick=self.link.callback(|_| Msg::SwitchTo(Scene::ConfigureGame))>{ "Reset Game" }</button>
                        <button disabled={app.get_state() != State::VictoryGameOver}
                                onclick=self.link.callback(|_| Msg::SwitchTo(Scene::GameOver))>{ "End Game" }</button>

                    {footer()}
                    </>
                }
            }
            Scene::GameOver => html! { <>
                {header()}

 { "Bye bye!" }

                    <button onclick=self.link.callback(|_| Msg::SwitchTo(Scene::ConfigureGame))>{ "No, Continue Playing" }</button>

                {footer()}
                </>
            },
        }
    }
}

/// Returns the columns and lines of the smallest
/// grid that can display this multi-line string `s`.
pub fn dimensions(s: &str) -> (usize, usize) {
    let mut row = 0;
    let mut col = 0;
    for l in s.lines() {
        let c = l.chars().count();
        if c > col {
            col = c;
        };
        row += 1;
    }
    (col, row)
}

#[wasm_bindgen(start)]
pub fn run_app() {
    App::<Model>::new().mount_to_body();
}

#[cfg(test)]
mod tests {
    use super::*;
    use secret::Secret;
    #[test]
    fn test_dimensions() {
        let secret = Secret::new("Lorem ipsum dolor sit amet, consectetur adipiscing\
         elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\
         quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure\
         dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur\
         sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est\
         laborum.");

        //secret.disclose_all();

        assert_eq!(dimensions(format!("{}", secret).as_str()), (68, 22));
        //assert_eq!(format!("{}", secret), String::new());
    }
}
<|endoftext|>


<commit_before>#![warn(clippy::pedantic)]

use fuzzy_matcher::skim::fuzzy_indices;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = console, js_name = log)]
    fn console_log(s: String);
}

#[allow(unused_macros)]
macro_rules! log {
    ($($t:tt)*) => (console_log(format_args!($($t)*).to_string()))
}

#[wasm_bindgen(start)]
pub fn start() {
    std::panic::set_hook(Box::new(console_error_panic_hook::hook));
}

#[wasm_bindgen]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SearchResult {
    pub index: usize,
    pub score: i32,
    indices: Vec<usize>,
}

#[wasm_bindgen]
#[derive(Debug)]
pub struct Searcher {
    names: Vec<String>,

    offset_mult: usize,
    offset_add: usize,
}

#[wasm_bindgen]
impl Searcher {
    #[wasm_bindgen(constructor)]
    pub fn new(capacity: usize, offset_mult: usize, offset_add: usize) -> Self {
        Self {
            names: Vec::with_capacity(capacity),

            offset_mult,
            offset_add,
        }
    }

    pub fn add_line(&mut self, line: String) {
        self.names.push(line)
    }

    pub fn search(&self, pattern: &str) -> Vec<u8> {
        let mut results: Vec<SearchResult> = self
            .names
            .iter()
            .enumerate()
            .filter_map(|(index, name)| {
                fuzzy_indices(name, pattern).map(|(score, indices)| SearchResult {
                    index: index * self.offset_mult + self.offset_add,
                    score: score as i32,
                    indices,
                })
            })
            .collect();

        results.sort_unstable_by_key(|result| (result.score, result.index));

        bincode::serialize(&results).unwrap()
    }
}

#[wasm_bindgen]
pub struct Collector {
    target_length: usize,
    sub_results: Vec<Vec<SearchResult>>,
}

#[wasm_bindgen]
impl Collector {
    #[wasm_bindgen(constructor)]
    pub fn new(target_length: usize) -> Self {
        Self {
            target_length,
            sub_results: Vec::with_capacity(target_length),
        }
    }

    pub fn collect(&mut self, blob: &[u8]) -> bool {
        let sub_result = bincode::deserialize(blob).unwrap();

        self.sub_results.push(sub_result);

        self.sub_results.len() == self.target_length
    }

    pub fn build(self) -> SearchResults {
        assert!(self.target_length == self.sub_results.len());

        let results: Vec<SearchResult> = self.sub_results
            .into_iter()
            .kmerge_by(|a, b| (a.score, a.index) > (b.score, b.index))
            .collect();

        SearchResults {
            results,
        }
    }
}

#[wasm_bindgen]
#[derive(Clone)]
pub struct SearchResults {
    results: Vec<SearchResult>,
}

#[wasm_bindgen]
impl SearchResults {
    pub fn empty() -> Self {
        Self {
            results: Vec::new(),
        }
    }

    pub fn get(&self, index: usize) -> SearchResult {
        self.results[index].clone()
    }

    pub fn length(&self) -> usize {
        self.results.len()
    }
}
<commit_msg>Fix sorting order<commit_after>#![warn(clippy::pedantic)]

use fuzzy_matcher::skim::fuzzy_indices;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = console, js_name = log)]
    fn console_log(s: String);
}

#[allow(unused_macros)]
macro_rules! log {
    ($($t:tt)*) => (console_log(format_args!($($t)*).to_string()))
}

#[wasm_bindgen(start)]
pub fn start() {
    std::panic::set_hook(Box::new(console_error_panic_hook::hook));
}

#[wasm_bindgen]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SearchResult {
    pub index: usize,
    pub score: i32,
    indices: Vec<usize>,
}

impl SearchResult {
    fn comparable(&self) -> impl Ord {
        (-self.score, self.index)
    }
}

#[wasm_bindgen]
#[derive(Debug)]
pub struct Searcher {
    names: Vec<String>,

    offset_mult: usize,
    offset_add: usize,
}

#[wasm_bindgen]
impl Searcher {
    #[wasm_bindgen(constructor)]
    pub fn new(capacity: usize, offset_mult: usize, offset_add: usize) -> Self {
        Self {
            names: Vec::with_capacity(capacity),

            offset_mult,
            offset_add,
        }
    }

    pub fn add_line(&mut self, line: String) {
        self.names.push(line)
    }

    pub fn search(&self, pattern: &str) -> Vec<u8> {
        let mut results: Vec<SearchResult> = self
            .names
            .iter()
            .enumerate()
            .filter_map(|(index, name)| {
                fuzzy_indices(name, pattern).map(|(score, indices)| SearchResult {
                    index: index * self.offset_mult + self.offset_add,
                    score: score as i32,
                    indices,
                })
            })
            .collect();

        results.sort_unstable_by_key(|result| result.comparable());

        bincode::serialize(&results).unwrap()
    }
}

#[wasm_bindgen]
pub struct Collector {
    target_length: usize,
    sub_results: Vec<Vec<SearchResult>>,
}

#[wasm_bindgen]
impl Collector {
    #[wasm_bindgen(constructor)]
    pub fn new(target_length: usize) -> Self {
        Self {
            target_length,
            sub_results: Vec::with_capacity(target_length),
        }
    }

    pub fn collect(&mut self, blob: &[u8]) -> bool {
        let sub_result = bincode::deserialize(blob).unwrap();

        self.sub_results.push(sub_result);

        self.sub_results.len() == self.target_length
    }

    pub fn build(self) -> SearchResults {
        assert!(self.target_length == self.sub_results.len());

        let results: Vec<SearchResult> = self
            .sub_results
            .into_iter()
            .kmerge_by(|a, b| a.comparable() < b.comparable())
            .collect();

        SearchResults { results }
    }
}

#[wasm_bindgen]
#[derive(Clone)]
pub struct SearchResults {
    results: Vec<SearchResult>,
}

#[wasm_bindgen]
impl SearchResults {
    pub fn empty() -> Self {
        Self {
            results: Vec::new(),
        }
    }

    pub fn get(&self, index: usize) -> SearchResult {
        self.results[index].clone()
    }

    pub fn length(&self) -> usize {
        self.results.len()
    }
}
<|endoftext|>


<commit_before>/*!
Simple persistent generic HashMap/Key-value store, using file locking to limit
writing between threads.

This is in a beta state at the moment.

Basic usage:

```
use typedb::{ KV, Value };

fn main() {
    let mut test_store = KV::<String, Value>::new("./basic.cab").unwrap();

    let _ = test_store.insert("key".to_string(), Value::String("value".to_string()));
    println!("{:?}", test_store.get(&"key".to_string()));
    let _ = test_store.remove(&"key".to_string());
}
```

Usage with user defined Key and Value types:

```
use typedb::{KV, key, value};
use serde_derive::{ Serialize, Deserialize };

key!(
enum MyKey {
    String(String),
    Int(i32),
});

value!(
enum MyValue {
    String(String),
    Int(i32),
});

fn main() {
    let mut test_store = KV::<MyKey, MyValue>::new("./types.cab").unwrap();

    let _ = test_store.insert(MyKey::Int(1i32), MyValue::String("value".to_string()));
    println!("{:?}", test_store.get(&MyKey::Int(1i32)));
    let _ = test_store.remove(&MyKey::Int(1i32));
}
```

*/

#![deny(missing_docs)]

extern crate bincode;
#[macro_use]
extern crate log;
extern crate persy;
extern crate serde;
#[macro_use]
extern crate serde_derive;

/// Macros for simplifying custom key and value types definition
pub mod macros;

use std::collections::HashMap;
use std::hash::Hash;

use bincode::{deserialize, serialize};
use serde::de::Deserialize;
use serde::ser::Serialize;

use persy::{Config, Persy, PersyError};

/// A default value type to use with KV
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub enum Value {
    /// Cab default Value type for strings
    String(String),
    /// Cab default Value type for intergers
    Int(i32),
    /// Cab default Value type for floats
    Float(f32),
    /// Cab default Value type for a sub map
    Map(HashMap<String, Value>),
    /// Cab default Value type for list
    List(Vec<Value>),
}

/// Type alias for results from KV
type KVResult = Result<bool, PersyError>;

/// Type alias for PersyError
type KVError = PersyError;

const SEGMENT_NAME: &str = "tdb";

/// The type that represents the key-value store
pub struct KV<K, V> {
    cab: HashMap<K, V>,
    persy: Persy,
    id: Option<persy::PersyId>,
}

impl<K, V> KV<K, V>
where
    K: Clone + Serialize + for<'kde> Deserialize<'kde> + Eq + Hash,
    V: Clone + Serialize + for<'vde> Deserialize<'vde>,
{
    /// Creates a new instance of the KV store
    pub fn new(p: &'static str) -> Result<KV<K, V>, PersyError> {
        // create and open the persy instance
        match Persy::create(p) {
            Ok(o) => o,
            Err(PersyError::Io(ref e)) if e.to_string() == "File exists (os error 17)" => (),
            Err(e) => return Err(e),
        }
        let persy = Persy::open(p, Config::new())?;

        // if the segment doesn't exist create
        if !persy.exists_segment(SEGMENT_NAME)? {
            let mut tx = persy.begin()?;
            persy.create_segment(&mut tx, SEGMENT_NAME)?;
            let prepared = persy.prepare_commit(tx)?;
            persy.commit(prepared)?;
        }

        let mut store = KV {
            cab: HashMap::new(),
            persy,
            id: None,
        };

        store.load_from_persist()?;

        Ok(store)
    }

    /// Inserta a key, value pair into the key-value store
    pub fn insert(&mut self, key: K, value: V) -> KVResult {
        // insert into the HashMap
        self.cab.insert(key, value);
        // persist
        self.write_to_persist()
    }

    /// Get the value from a key
    pub fn get(&mut self, key: &K) -> Result<Option<V>, KVError> {
        // get the value from the cab
        Ok(self.cab.get(&key).map(|v| (*v).clone()))
    }

    /// Removes a key and associated value from the key-value Store
    pub fn remove(&mut self, key: &K) -> KVResult {
        // remove from the HashMap
        self.cab.remove(&key);
        // persist
        self.write_to_persist()
    }

    /// get all the keys contained in the KV Store
    pub fn keys(&mut self) -> Result<Vec<K>, KVError> {
        // create a vec from the cabs keys
        Ok(self.cab.keys().cloned().collect())
    }

    /// Writes the key-value Store to file
    fn write_to_persist(&mut self) -> KVResult {
        // attempt to write to the cab
        let mut tx = self.persy.begin()?;

        // serialize the cab as a u8 vec
        let byte_vec: Vec<u8> = match serialize(&self.cab) {
            Ok(bv) => bv,
            Err(e) => {
                error!("serialize: {}", e);
                return Err(PersyError::Custom(e));
            }
        };

        match &self.id {
            Some(ref x) => self
                .persy
                .update_record(&mut tx, SEGMENT_NAME, x, &byte_vec)?,
            None => self.id = Some(self.persy.insert_record(&mut tx, SEGMENT_NAME, &byte_vec)?),
        }

        let prepared = self.persy.prepare_commit(tx)?;
        self.persy.commit(prepared)?;

        Ok(true)
    }

    /// Loads key-value store from file
    fn load_from_persist(&mut self) -> KVResult {
        if self.persy.exists_segment(SEGMENT_NAME)? {
            let deserbv = |byte_vec: &Vec<u8>| {
                // deserialize u8 vec back into HashMap
                match deserialize(byte_vec.as_slice()) {
                    Ok(f) => {
                        // assign read HashMap back to self
                        Ok(f)
                    }
                    Err(e) => {
                        error!("{}", e);
                        Err(PersyError::Custom(e))
                    }
                }
            };
            if let Some(ref x) = &self.id {
                if let Some(byte_vec) = self.persy.read_record(SEGMENT_NAME, x)? {
                    self.cab = deserbv(&byte_vec)?;
                    return Ok(true);
                }
            }
            for (id, byte_vec) in self.persy.scan(SEGMENT_NAME)? {
                self.cab = deserbv(&byte_vec)?;
                self.id = Some(id);
            }
        }

        Ok(true)
    }
}
<commit_msg>Refactor deserialisation from a closure to fn<commit_after>/*!
Simple persistent generic HashMap/Key-value store, using file locking to limit
writing between threads.

This is in a beta state at the moment.

Basic usage:

```
use typedb::{ KV, Value };

fn main() {
    let mut test_store = KV::<String, Value>::new("./basic.cab").unwrap();

    let _ = test_store.insert("key".to_string(), Value::String("value".to_string()));
    println!("{:?}", test_store.get(&"key".to_string()));
    let _ = test_store.remove(&"key".to_string());
}
```

Usage with user defined Key and Value types:

```
use typedb::{KV, key, value};
use serde_derive::{ Serialize, Deserialize };

key!(
enum MyKey {
    String(String),
    Int(i32),
});

value!(
enum MyValue {
    String(String),
    Int(i32),
});

fn main() {
    let mut test_store = KV::<MyKey, MyValue>::new("./types.cab").unwrap();

    let _ = test_store.insert(MyKey::Int(1i32), MyValue::String("value".to_string()));
    println!("{:?}", test_store.get(&MyKey::Int(1i32)));
    let _ = test_store.remove(&MyKey::Int(1i32));
}
```

*/

#![deny(missing_docs)]

extern crate bincode;
#[macro_use]
extern crate log;
extern crate persy;
extern crate serde;
#[macro_use]
extern crate serde_derive;

/// Macros for simplifying custom key and value types definition
pub mod macros;

use std::collections::HashMap;
use std::hash::Hash;

use bincode::{deserialize, serialize};
use serde::de::Deserialize;
use serde::ser::Serialize;

use persy::{Config, Persy, PersyError};

/// A default value type to use with KV
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub enum Value {
    /// Cab default Value type for strings
    String(String),
    /// Cab default Value type for intergers
    Int(i32),
    /// Cab default Value type for floats
    Float(f32),
    /// Cab default Value type for a sub map
    Map(HashMap<String, Value>),
    /// Cab default Value type for list
    List(Vec<Value>),
}

/// Type alias for results from KV
type KVResult = Result<bool, PersyError>;

/// Type alias for PersyError
type KVError = PersyError;

const SEGMENT_NAME: &str = "tdb";

/// The type that represents the key-value store
pub struct KV<K, V> {
    cab: HashMap<K, V>,
    persy: Persy,
    id: Option<persy::PersyId>,
}

impl<K, V> KV<K, V>
where
    K: Clone + Serialize + for<'kde> Deserialize<'kde> + Eq + Hash,
    V: Clone + Serialize + for<'vde> Deserialize<'vde>,
{
    /// Creates a new instance of the KV store
    pub fn new(p: &'static str) -> Result<KV<K, V>, PersyError> {
        // create and open the persy instance
        match Persy::create(p) {
            Ok(o) => o,
            Err(PersyError::Io(ref e)) if e.to_string() == "File exists (os error 17)" => (),
            Err(e) => return Err(e),
        }
        let persy = Persy::open(p, Config::new())?;

        // if the segment doesn't exist create
        if !persy.exists_segment(SEGMENT_NAME)? {
            let mut tx = persy.begin()?;
            persy.create_segment(&mut tx, SEGMENT_NAME)?;
            let prepared = persy.prepare_commit(tx)?;
            persy.commit(prepared)?;
        }

        let mut store = KV {
            cab: HashMap::new(),
            persy,
            id: None,
        };

        store.load_from_persist()?;

        Ok(store)
    }

    /// Inserta a key, value pair into the key-value store
    pub fn insert(&mut self, key: K, value: V) -> KVResult {
        // insert into the HashMap
        self.cab.insert(key, value);
        // persist
        self.write_to_persist()
    }

    /// Get the value from a key
    pub fn get(&mut self, key: &K) -> Result<Option<V>, KVError> {
        // get the value from the cab
        Ok(self.cab.get(&key).map(|v| (*v).clone()))
    }

    /// Removes a key and associated value from the key-value Store
    pub fn remove(&mut self, key: &K) -> KVResult {
        // remove from the HashMap
        self.cab.remove(&key);
        // persist
        self.write_to_persist()
    }

    /// get all the keys contained in the KV Store
    pub fn keys(&mut self) -> Result<Vec<K>, KVError> {
        // create a vec from the cabs keys
        Ok(self.cab.keys().cloned().collect())
    }

    /// Writes the key-value Store to file
    fn write_to_persist(&mut self) -> KVResult {
        // attempt to write to the cab
        let mut tx = self.persy.begin()?;

        // serialize the cab as a u8 vec
        let byte_vec: Vec<u8> = match serialize(&self.cab) {
            Ok(bv) => bv,
            Err(e) => {
                error!("serialize: {}", e);
                return Err(PersyError::Custom(e));
            }
        };

        match &self.id {
            Some(ref x) => self
                .persy
                .update_record(&mut tx, SEGMENT_NAME, x, &byte_vec)?,
            None => self.id = Some(self.persy.insert_record(&mut tx, SEGMENT_NAME, &byte_vec)?),
        }

        let prepared = self.persy.prepare_commit(tx)?;
        self.persy.commit(prepared)?;

        Ok(true)
    }

    /// deserialize u8 vec back into HashMap
    fn deserialize_byte_vec(byte_vec: &Vec<u8>) -> Result<HashMap<K, V>, PersyError> {
        match deserialize(byte_vec.as_slice()) {
            Ok(f) => {
                Ok(f)
            }
            Err(e) => {
                error!("{}", e);
                Err(PersyError::Custom(e))
            }
        }
    }

    /// Loads key-value store from file
    fn load_from_persist(&mut self) -> KVResult {
        if self.persy.exists_segment(SEGMENT_NAME)? {
            if let Some(ref x) = &self.id {
                if let Some(byte_vec) = self.persy.read_record(SEGMENT_NAME, x)? {
                    self.cab = KV::deserialize_byte_vec(&byte_vec)?;
                    return Ok(true);
                }
            }
            for (id, byte_vec) in self.persy.scan(SEGMENT_NAME)? {
                self.cab = KV::deserialize_byte_vec(&byte_vec)?;
                self.id = Some(id);
            }
        }

        Ok(true)
    }
}
<|endoftext|>


<commit_before>//use std;
use std::slice::*;

const K : [u32; 64] = [
	0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
	0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
	0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
	0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
	0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
	0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
	0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
	0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
	0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
	0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
	0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
	0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
	0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
	0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
	0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
	0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
];

const S : [u32; 64] =
[
	7, 12, 17, 22, 7, 12, 17, 22, 7, 12,
	17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5,
	9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4,
	11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
	4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21,
	6, 10, 15, 21, 6, 10, 15, 21
];

const BLOCK_SIZE : usize = 64;

#[derive(Copy)]
pub struct Md5 {
		a0 : u32,
		b0 : u32,
		c0 : u32,
		d0 : u32,
		end_of_buffer : usize,
		length_so_far : usize,
		buffer : [u8; BLOCK_SIZE],
}

struct StateVector {
		a : u32,
	    b : u32,
	    c : u32,
	    d : u32,
	}

impl Clone for Md5 {
    fn clone(&self) -> Md5 {
    		return Md5 {
				a0: self.a0,
				b0: self.b0,
				c0: self.c0,
				d0: self.d0,
				buffer: self.buffer,
				end_of_buffer: self.end_of_buffer,
				length_so_far: self.length_so_far,
			}
    }
}

impl Md5 {
	pub fn new() -> Md5 {
		return Md5 {
			a0: 0x67452301,
			b0: 0xefcdab89,
			c0: 0x98badcfe,
			d0: 0x10325476,
			buffer: [0; BLOCK_SIZE],
			end_of_buffer: 0,
			length_so_far: 0,
		}
	}

	pub fn update(&mut self, bytes : &[u8]) -> &mut Md5 {

		let remaining_space = BLOCK_SIZE - self.end_of_buffer;
		let bytes_length = bytes.len();

		if remaining_space > bytes_length {
			let ptr = &mut self.buffer[BLOCK_SIZE-remaining_space.. BLOCK_SIZE-remaining_space+bytes.len()];
			ptr.clone_from_slice(&bytes[0..bytes_length]);
			self.length_so_far += bytes_length;
			self.end_of_buffer += bytes_length;
		}
		else{
			{
				let ptr = &mut self.buffer[BLOCK_SIZE - remaining_space .. BLOCK_SIZE];
				ptr.clone_from_slice(&bytes[0..remaining_space]);
			}
			self.end_of_buffer = 0;
			self.length_so_far += remaining_space;
			self.compute_block(None);

			let total_blocks = (bytes_length - remaining_space) / 64;

			for i in 0..total_blocks {
				let start_index = i*BLOCK_SIZE + remaining_space;
				self.compute_block(Some(&bytes[start_index..start_index+BLOCK_SIZE]));
				self.length_so_far += BLOCK_SIZE;
			}

			let leftover = (bytes_length - remaining_space) % 64;
			let buffer_ptr = &mut self.buffer[0..leftover];
			buffer_ptr.clone_from_slice(&bytes[bytes_length-leftover..bytes_length]);
			self.end_of_buffer += leftover;
			self.length_so_far += leftover;
		}
		return self
	}

	fn compute_block(&mut self, input : Option<&[u8]>) {

		let data : &[u8] = match input {
			Some(a) => a,
			None => &self.buffer
		};

		let mut m : [u32; 16] = [0;16];

		for i in 0..16 {
			m[i] = from_le_bytes(data[4*i+0], data[4*i+1], data[4*i+2], data[4*i+3]);
		}

		let m = m;

		let mut f : u32;
		let mut g : u32;

		let mut sv = StateVector{
				a:self.a0,
				b:self.b0,
				c:self.c0,
				d:self.d0,
		};

		for i in 0..16 {
			f = (sv.b & sv.c) | (!sv.b & sv.d);
		    g = i;
    		Md5::update_state(&mut sv, &m, i, f, g);
		}

		for j in 0..16 {
			let i = j+16;
			f = (sv.d & sv.b) | (!sv.d & sv.c);
           	g = (5*i + 1) % 16;
    		Md5::update_state(&mut sv, &m, i, f, g);
		}

		for j in 0..16 {
			let i = j+32;
			f = sv.b ^ sv.c ^ sv.d;
            g = (3*i + 5) % 16;
    		Md5::update_state(&mut sv, &m, i, f, g);
		}

		for j in 0..16 {
			let i = j+48;
			f = sv.c ^ (sv.b | !sv.d);
            g = (7*i) % 16;
         	Md5::update_state(&mut sv, &m, i, f, g);
		}
	    self.a0 = self.a0.wrapping_add(sv.a);
	    self.b0 = self.b0.wrapping_add(sv.b);
	    self.c0 = self.c0.wrapping_add(sv.c);
	    self.d0 = self.d0.wrapping_add(sv.d);
	}

	#[inline(always)]
	fn update_state(sv : &mut StateVector, m : &[u32; 16], i : u32, f : u32, g : u32) {
		let d_temp = sv.d;
        sv.d = sv.c;
        sv.c = sv.b;
        sv.b = sv.b.wrapping_add(sv.a.wrapping_add(f).wrapping_add(K[i as usize]).wrapping_add(m[g as usize]).rotate_left(S[i as usize]));
        sv.a = d_temp;
	}

	fn complete_data(&self) -> Md5 {

		let mut temp = self.clone();

		temp.update(&[0b10000000u8]);

		let mod512 = temp.end_of_buffer;
		let padding_length =
			if mod512 > 56
				{ 64-mod512+56 }
			else
				{ 56 - mod512 };

		for _ in 0..padding_length {
			temp.update(&[0]);
		}

		let size  = 8*self.length_so_far as u64;
		let mut size_bytes : [u8; 8] = [0; 8];
		for i in 0..8 {
			size_bytes[i] = (size.wrapping_shr(8*(i as u32)) % 256) as u8;
		}
		temp.update(&size_bytes);

		return temp;
	}

	pub fn hexdigest(&self) -> [u8;16] {

		let completedhash = self.complete_data();

		let mut result = [0u8; 16];
		for (index, v) in [completedhash.a0, completedhash.b0, completedhash.c0, completedhash.d0].iter().enumerate() {
			let bytes = to_le_bytes(v);
			result[4*index] = bytes.0;
			result[4*index+1] = bytes.1;
			result[4*index+2] = bytes.2;
			result[4*index+3] = bytes.3;
		}

		return result;
	}
}

pub fn to_hex_string(bytes: &[u8]) -> String {
  let strs: Vec<String> = bytes.iter().map(|b| format!("{:02X}", b)).collect();
  strs.join("")
}

#[inline(always)]
fn to_le_bytes(i: &u32) -> (u8, u8, u8, u8) {
	let q1 = (i >> 24u32) % 256;
	let q2 = (i >> 16u32) % 256;
	let q3 = (i >> 8u32)  % 256;
	let q4 = (i >> 0u32)  % 256;
	return (q4 as u8, q3 as u8, q2 as u8, q1 as u8)
}

#[inline(always)]
fn from_le_bytes(a: u8, b:u8, c:u8, d:u8) -> u32 {
	return (a as u32) + ((b as u32) << 8) + ((c as u32) << 16) + ((d as u32) << 24);
}

mod tests {

	use super::*;

	#[test]
	fn empty_object_test() {

		let mut hash = Md5::new();
		let vals = vec![];
		hash.update(&vals);
		let trueans = "D41D8CD98F00B204E9800998ECF8427E";
		let ans = hash.hexdigest();

		assert!(to_hex_string(&ans) == trueans);
	}

	#[test]
	fn seven_hundred_as() {
		let mut hash = Md5::new();
		let a = 'A' as u8;
		let vals = vec![a; 700];
		hash.update(&vals);
		let trueans = "C04C6D6896853D32B720D69A6027E6BE";
		let ans = hash.hexdigest();

		assert!(to_hex_string(&ans) == trueans);
	}

	#[test]
	fn associativity_test() {

		let mut hash = Md5::new();
		let vals = vec![b'B'; 32];
    	let mut vals2 = Vec::new();
	    vals2.resize(64, b'A');

	    hash.update(&vals);
	    hash.update(&vals2);

	    let mut vals3 = vec![b'A'; 32+64];
	    for i in 0..32 {
	        vals3[i]=b'B';
	    }

	    let mut secondhash = Md5::new();
	    secondhash.update(&vals3);

		let ans = hash.hexdigest();
		let ans2 = secondhash.hexdigest();
		assert!(to_hex_string(&ans) == to_hex_string(&ans2));
	}

}
<commit_msg>Cosmetic fixes<commit_after>
const K : [u32; 64] = [
	0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
	0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
	0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
	0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
	0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
	0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
	0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
	0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
	0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
	0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
	0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
	0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
	0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
	0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
	0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
	0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
];

const S : [u32; 64] =
[
	7, 12, 17, 22, 7, 12, 17, 22, 7, 12,
	17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5,
	9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4,
	11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
	4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21,
	6, 10, 15, 21, 6, 10, 15, 21
];

const BLOCK_SIZE : usize = 64;

#[derive(Copy)]
struct StateVector {
		a : u32,
	    b : u32,
	    c : u32,
	    d : u32,
}

impl Clone for StateVector {
    fn clone(&self) -> StateVector {
    	return StateVector {
	    	a: self.a,
	    	b: self.b,
	    	c: self.c,
	    	d: self.d
	    }
    }
}

#[derive(Copy)]
pub struct Md5 {
		state : StateVector,
		end_of_buffer : usize,
		length_so_far : usize,
		buffer : [u8; BLOCK_SIZE],
}

impl Clone for Md5 {
    fn clone(&self) -> Md5 {
    		return Md5 {
    			state : self.state,
				buffer: self.buffer,
				end_of_buffer: self.end_of_buffer,
				length_so_far: self.length_so_far,
			}
    }
}

impl Md5 {
	pub fn new() -> Md5 {
		return Md5 {
			state: StateVector {
				a: 0x67452301,
				b: 0xefcdab89,
				c: 0x98badcfe,
				d: 0x10325476,
				},
			buffer: [0; BLOCK_SIZE],
			end_of_buffer: 0,
			length_so_far: 0,
		}
	}

	pub fn update(&mut self, bytes : &[u8]) -> &mut Md5 {

		let remaining_space = BLOCK_SIZE - self.end_of_buffer;
		let bytes_length = bytes.len();

		if remaining_space > bytes_length {
			let ptr = &mut self.buffer[BLOCK_SIZE-remaining_space.. BLOCK_SIZE-remaining_space+bytes.len()];
			ptr.clone_from_slice(&bytes[0..bytes_length]);
			self.length_so_far += bytes_length;
			self.end_of_buffer += bytes_length;
		}
		else{
			{
				let ptr = &mut self.buffer[BLOCK_SIZE - remaining_space .. BLOCK_SIZE];
				ptr.clone_from_slice(&bytes[0..remaining_space]);
			}
			self.end_of_buffer = 0;
			self.length_so_far += remaining_space;
			self.compute_block(None);

			let total_blocks = (bytes_length - remaining_space) / 64;

			for i in 0..total_blocks {
				let start_index = i*BLOCK_SIZE + remaining_space;
				self.compute_block(Some(&bytes[start_index..start_index+BLOCK_SIZE]));
				self.length_so_far += BLOCK_SIZE;
			}

			let leftover = (bytes_length - remaining_space) % 64;
			let buffer_ptr = &mut self.buffer[0..leftover];
			buffer_ptr.clone_from_slice(&bytes[bytes_length-leftover..bytes_length]);
			self.end_of_buffer += leftover;
			self.length_so_far += leftover;
		}
		return self
	}

	fn compute_block(&mut self, input : Option<&[u8]>) {

		let data : &[u8] = match input {
			Some(a) => a,
			None => &self.buffer
		};

		let mut m : [u32; 16] = [0;16];

		for i in 0..16 {
			m[i] = from_le_bytes(data[4*i+0], data[4*i+1], data[4*i+2], data[4*i+3]);
		}

		let m = m;

		let mut f : u32;
		let mut g : u32;

		let mut sv = self.state;

		for i in 0..16 {
			f = (sv.b & sv.c) | (!sv.b & sv.d);
		    g = i;
    		Md5::update_state(&mut sv, &m, i, f, g);
		}

		for j in 0..16 {
			let i = j+16;
			f = (sv.d & sv.b) | (!sv.d & sv.c);
           	g = (5*i + 1) % 16;
    		Md5::update_state(&mut sv, &m, i, f, g);
		}

		for j in 0..16 {
			let i = j+32;
			f = sv.b ^ sv.c ^ sv.d;
            g = (3*i + 5) % 16;
    		Md5::update_state(&mut sv, &m, i, f, g);
		}

		for j in 0..16 {
			let i = j+48;
			f = sv.c ^ (sv.b | !sv.d);
            g = (7*i) % 16;
         	Md5::update_state(&mut sv, &m, i, f, g);
		}
	    self.state.a = self.state.a.wrapping_add(sv.a);
	    self.state.b = self.state.b.wrapping_add(sv.b);
	    self.state.c = self.state.c.wrapping_add(sv.c);
	    self.state.d = self.state.d.wrapping_add(sv.d);
	}

	#[inline(always)]
	fn update_state(sv : &mut StateVector, m : &[u32; 16], i : u32, f : u32, g : u32) {
		let d_temp = sv.d;
        sv.d = sv.c;
        sv.c = sv.b;
        sv.b = sv.b.wrapping_add(sv.a.wrapping_add(f).wrapping_add(K[i as usize]).wrapping_add(m[g as usize]).rotate_left(S[i as usize]));
        sv.a = d_temp;
	}

	fn complete_data(&self) -> Md5 {

		let mut temp = self.clone();

		temp.update(&[0b10000000u8]);

		let mod512 = temp.end_of_buffer;
		let padding_length =
			if mod512 > 56
				{ 64-mod512+56 }
			else
				{ 56 - mod512 };

		for _ in 0..padding_length {
			temp.update(&[0]);
		}

		let size  = 8*self.length_so_far as u64;
		let mut size_bytes : [u8; 8] = [0; 8];
		for i in 0..8 {
			size_bytes[i] = (size.wrapping_shr(8*(i as u32)) % 256) as u8;
		}
		temp.update(&size_bytes);

		return temp;
	}

	pub fn hexdigest(&self) -> [u8;16] {

		let completedhash = self.complete_data();

		let mut result = [0u8; 16];
		for (index, v) in [completedhash.state.a, completedhash.state.b, completedhash.state.c, completedhash.state.d].iter().enumerate() {
			let bytes = to_le_bytes(v);
			result[4*index] = bytes.0;
			result[4*index+1] = bytes.1;
			result[4*index+2] = bytes.2;
			result[4*index+3] = bytes.3;
		}

		return result;
	}
}

pub fn to_hex_string(bytes: &[u8]) -> String {
  let strs: Vec<String> = bytes.iter().map(|b| format!("{:02X}", b)).collect();
  strs.join("")
}

#[inline(always)]
fn to_le_bytes(i: &u32) -> (u8, u8, u8, u8) {
	let q1 = (i >> 24u32) % 256;
	let q2 = (i >> 16u32) % 256;
	let q3 = (i >> 8u32)  % 256;
	let q4 = (i >> 0u32)  % 256;
	return (q4 as u8, q3 as u8, q2 as u8, q1 as u8)
}

#[inline(always)]
fn from_le_bytes(a: u8, b:u8, c:u8, d:u8) -> u32 {
	return (a as u32) + ((b as u32) << 8) + ((c as u32) << 16) + ((d as u32) << 24);
}

#[cfg(test)]
mod tests {

	use super::*;

	#[test]
	fn empty_object_test() {

		let mut hash = Md5::new();
		let vals = vec![];
		hash.update(&vals);
		let trueans = "D41D8CD98F00B204E9800998ECF8427E";
		let ans = hash.hexdigest();

		assert!(to_hex_string(&ans) == trueans);
	}

	#[test]
	fn seven_hundred_as() {
		let mut hash = Md5::new();
		let a = 'A' as u8;
		let vals = vec![a; 700];
		hash.update(&vals);
		let trueans = "C04C6D6896853D32B720D69A6027E6BE";
		let ans = hash.hexdigest();

		assert!(to_hex_string(&ans) == trueans);
	}

	#[test]
	fn associativity_test() {

		let mut hash = Md5::new();
		let vals = vec![b'B'; 32];
    	let mut vals2 = Vec::new();
	    vals2.resize(64, b'A');

	    hash.update(&vals);
	    hash.update(&vals2);

	    let mut vals3 = vec![b'A'; 32+64];
	    for i in 0..32 {
	        vals3[i]=b'B';
	    }

	    let mut secondhash = Md5::new();
	    secondhash.update(&vals3);

		let ans = hash.hexdigest();
		let ans2 = secondhash.hexdigest();
		assert!(to_hex_string(&ans) == to_hex_string(&ans2));
	}

}
<|endoftext|>


<commit_before>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a microkernel that supports `x86_64` systems and
//! provides Unix-like syscalls for primarily Rust applications

//#![deny(warnings)]
#![cfg_attr(feature = "clippy", allow(if_same_then_else))]
#![cfg_attr(feature = "clippy", allow(inline_always))]
#![cfg_attr(feature = "clippy", allow(many_single_char_names))]
#![cfg_attr(feature = "clippy", allow(module_inception))]
#![cfg_attr(feature = "clippy", allow(new_without_default))]
#![cfg_attr(feature = "clippy", allow(not_unsafe_ptr_arg_deref))]
#![cfg_attr(feature = "clippy", allow(or_fun_call))]
#![cfg_attr(feature = "clippy", allow(too_many_arguments))]
#![feature(alloc)]
#![feature(allocator_api)]
#![feature(asm)]
#![feature(concat_idents)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(integer_atomics)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(never_type)]
#![feature(ptr_internals)]
#![feature(thread_local)]
#![no_std]

pub extern crate x86;

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate linked_list_allocator;
extern crate spin;
#[cfg(feature = "slab")]
extern crate slab_allocator;

use alloc::vec::Vec;
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

use scheme::{FileHandle, SchemeNamespace};

pub use consts::*;

#[macro_use]
/// Shared data structures
pub mod common;

/// Architecture-dependent stuff
#[macro_use]
pub mod arch;
pub use arch::*;

/// Constants like memory locations
pub mod consts;

/// Heap allocators
pub mod allocator;

/// ACPI table parsing
#[cfg(feature = "acpi")]
mod acpi;

/// Context management
pub mod context;

/// Architecture-independent devices
pub mod devices;

/// ELF file parsing
#[cfg(not(feature="doc"))]
pub mod elf;

/// Event handling
pub mod event;

/// External functions
pub mod externs;

/// Memory management
pub mod memory;

/// Panic
#[cfg(not(any(feature="doc", test)))]
pub mod panic;

/// Schemes, filesystem handlers
pub mod scheme;

/// Synchronization primitives
pub mod sync;

/// Syscall handlers
pub mod syscall;

/// Time
pub mod time;

/// Tests
#[cfg(test)]
pub mod tests;

#[global_allocator]
static ALLOCATOR: allocator::Allocator = allocator::Allocator;

/// A unique number that identifies the current CPU - used for scheduling
#[thread_local]
static CPU_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the current CPU's scheduling ID
#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

/// The count of all CPUs that can have work scheduled
static CPU_COUNT : AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the number of CPUs currently active
#[inline(always)]
pub fn cpu_count() -> usize {
    CPU_COUNT.load(Ordering::Relaxed)
}

static mut INIT_ENV: &[u8] = &[];

/// Initialize userspace by running the initfs:bin/init process
/// This function will also set the CWD to initfs:bin and open debug: as stdio
pub extern fn userspace_init() {
    let path = b"initfs:/bin/init";
    let env = unsafe { INIT_ENV };

    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));

    assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2));

    let fd = syscall::open(path, syscall::flag::O_RDONLY).expect("failed to open init");

    let mut args = Vec::new();
    args.push(path.to_vec().into_boxed_slice());

    let mut vars = Vec::new();
    for var in env.split(|b| *b == b'\n') {
        vars.push(var.to_vec().into_boxed_slice());
    }

    syscall::fexec_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice()).expect("failed to execute init");

    panic!("init returned");
}

/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
pub fn kmain(cpus: usize, env: &'static [u8]) -> ! {
    CPU_ID.store(0, Ordering::SeqCst);
    CPU_COUNT.store(cpus, Ordering::SeqCst);
    unsafe { INIT_ENV = env };

    //Initialize the first context, stored in kernel/src/context/mod.rs
    context::init();

    let pid = syscall::getpid();
    println!("BSP: {:?} {}", pid, cpus);
    println!("Env: {:?}", ::core::str::from_utf8(env));

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.rns = SchemeNamespace::from(1);
            context.ens = SchemeNamespace::from(1);
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
}

/// This is the main kernel entry point for secondary CPUs
#[allow(unreachable_code, unused_variables)]
pub fn kmain_ap(id: usize) -> ! {
    CPU_ID.store(id, Ordering::SeqCst);

    if cfg!(feature = "multi_core") {
        context::init();

        let pid = syscall::getpid();
        println!("AP {}: {:?}", id, pid);

        loop {
            unsafe {
                interrupt::disable();
                if context::switch() {
                    interrupt::enable_and_nop();
                } else {
                    // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                    interrupt::enable_and_halt();
                }
            }
        }
    } else {
        println!("AP {}: Disabled", id);

        loop {
            unsafe {
                interrupt::disable();
                interrupt::halt();
            }
        }
    }
}

/// Allow exception handlers to send signal to arch-independant kernel
#[no_mangle]
pub extern fn ksignal(signal: usize) {
    println!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id());
    {
        let contexts = context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
        }
    }
    syscall::exit(signal & 0x7F);
}
<commit_msg>Prevent adding empty variables to environment<commit_after>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a microkernel that supports `x86_64` systems and
//! provides Unix-like syscalls for primarily Rust applications

//#![deny(warnings)]
#![cfg_attr(feature = "clippy", allow(if_same_then_else))]
#![cfg_attr(feature = "clippy", allow(inline_always))]
#![cfg_attr(feature = "clippy", allow(many_single_char_names))]
#![cfg_attr(feature = "clippy", allow(module_inception))]
#![cfg_attr(feature = "clippy", allow(new_without_default))]
#![cfg_attr(feature = "clippy", allow(not_unsafe_ptr_arg_deref))]
#![cfg_attr(feature = "clippy", allow(or_fun_call))]
#![cfg_attr(feature = "clippy", allow(too_many_arguments))]
#![feature(alloc)]
#![feature(allocator_api)]
#![feature(asm)]
#![feature(concat_idents)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(integer_atomics)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(never_type)]
#![feature(ptr_internals)]
#![feature(thread_local)]
#![no_std]

pub extern crate x86;

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate linked_list_allocator;
extern crate spin;
#[cfg(feature = "slab")]
extern crate slab_allocator;

use alloc::vec::Vec;
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

use scheme::{FileHandle, SchemeNamespace};

pub use consts::*;

#[macro_use]
/// Shared data structures
pub mod common;

/// Architecture-dependent stuff
#[macro_use]
pub mod arch;
pub use arch::*;

/// Constants like memory locations
pub mod consts;

/// Heap allocators
pub mod allocator;

/// ACPI table parsing
#[cfg(feature = "acpi")]
mod acpi;

/// Context management
pub mod context;

/// Architecture-independent devices
pub mod devices;

/// ELF file parsing
#[cfg(not(feature="doc"))]
pub mod elf;

/// Event handling
pub mod event;

/// External functions
pub mod externs;

/// Memory management
pub mod memory;

/// Panic
#[cfg(not(any(feature="doc", test)))]
pub mod panic;

/// Schemes, filesystem handlers
pub mod scheme;

/// Synchronization primitives
pub mod sync;

/// Syscall handlers
pub mod syscall;

/// Time
pub mod time;

/// Tests
#[cfg(test)]
pub mod tests;

#[global_allocator]
static ALLOCATOR: allocator::Allocator = allocator::Allocator;

/// A unique number that identifies the current CPU - used for scheduling
#[thread_local]
static CPU_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the current CPU's scheduling ID
#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

/// The count of all CPUs that can have work scheduled
static CPU_COUNT : AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the number of CPUs currently active
#[inline(always)]
pub fn cpu_count() -> usize {
    CPU_COUNT.load(Ordering::Relaxed)
}

static mut INIT_ENV: &[u8] = &[];

/// Initialize userspace by running the initfs:bin/init process
/// This function will also set the CWD to initfs:bin and open debug: as stdio
pub extern fn userspace_init() {
    let path = b"initfs:/bin/init";
    let env = unsafe { INIT_ENV };

    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));

    assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2));

    let fd = syscall::open(path, syscall::flag::O_RDONLY).expect("failed to open init");

    let mut args = Vec::new();
    args.push(path.to_vec().into_boxed_slice());

    let mut vars = Vec::new();
    for var in env.split(|b| *b == b'\n') {
        if ! var.is_empty() {
            vars.push(var.to_vec().into_boxed_slice());
        }
    }

    syscall::fexec_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice()).expect("failed to execute init");

    panic!("init returned");
}

/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
pub fn kmain(cpus: usize, env: &'static [u8]) -> ! {
    CPU_ID.store(0, Ordering::SeqCst);
    CPU_COUNT.store(cpus, Ordering::SeqCst);
    unsafe { INIT_ENV = env };

    //Initialize the first context, stored in kernel/src/context/mod.rs
    context::init();

    let pid = syscall::getpid();
    println!("BSP: {:?} {}", pid, cpus);
    println!("Env: {:?}", ::core::str::from_utf8(env));

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.rns = SchemeNamespace::from(1);
            context.ens = SchemeNamespace::from(1);
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
}

/// This is the main kernel entry point for secondary CPUs
#[allow(unreachable_code, unused_variables)]
pub fn kmain_ap(id: usize) -> ! {
    CPU_ID.store(id, Ordering::SeqCst);

    if cfg!(feature = "multi_core") {
        context::init();

        let pid = syscall::getpid();
        println!("AP {}: {:?}", id, pid);

        loop {
            unsafe {
                interrupt::disable();
                if context::switch() {
                    interrupt::enable_and_nop();
                } else {
                    // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                    interrupt::enable_and_halt();
                }
            }
        }
    } else {
        println!("AP {}: Disabled", id);

        loop {
            unsafe {
                interrupt::disable();
                interrupt::halt();
            }
        }
    }
}

/// Allow exception handlers to send signal to arch-independant kernel
#[no_mangle]
pub extern fn ksignal(signal: usize) {
    println!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id());
    {
        let contexts = context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
        }
    }
    syscall::exit(signal & 0x7F);
}
<|endoftext|>


<commit_before>extern crate time;

use std::fmt;

pub enum TestResult {
    Pass,
    Fail,
    Error,
    Skipped
}

impl fmt::Display for TestResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let rep = match *self {
            TestResult::Pass => ".",
            TestResult::Fail => "F",
            TestResult::Error => "E",
            TestResult::Skipped => "S"
        };
        write!(f, "{}", rep)
    }
}

pub trait Runnable {
    fn run(&self) -> TestResult;
}

struct TestStats {
    runs: usize,
    failures: usize,
    errors: usize,
    skips: usize,
}

impl TestStats {
    fn new() -> TestStats {
        TestStats {
            runs: 0,
            failures: 0,
            errors: 0,
            skips: 0
        }
    }

    fn create(result: &TestResult) -> TestStats {
        TestStats {
            runs: 1,
            failures: match *result { TestResult::Fail => 1, _ => 0 },
            errors: match *result { TestResult::Error => 1, _ => 0 },
            skips: match *result { TestResult::Skipped => 1, _ => 0 },
        }
    }

    fn combine(a: TestStats, b: TestStats) -> TestStats {
        TestStats {
            runs: a.runs + b.runs,
            failures: a.failures + b.failures,
            errors: a.errors + b.errors,
            skips: a.skips + b.skips
        }
    }
}

pub struct TestRunner;

impl TestRunner {
    pub fn run(&self, tests: &Vec<Box<Runnable>>) {
        use std::io::{Write,stdout};

        println!("# Running.\n");

        let start_time = time::precise_time_ns();

        let mut results: Vec<TestResult>;

        {
            let out = stdout();
            let mut lock = out.lock();

            results = tests
                .iter()
                .map(|test| {
                    let result = test.run();
                    match write!(&mut lock, "{}", result) {
                        Ok(_) => match lock.flush() {
                            Ok(_) => {},
                            _ => panic!("Unable to flush test result")
                        },
                        _ => panic!("Unable to write test result")
                    };
                    result
                })
                .collect();
        }

        let end_time = time::precise_time_ns();
        let time_ms = end_time.wrapping_sub(start_time) as i64 / 1000000;
        let time_s = time_ms as f64 / 1000f64;
        let runs_f = results.len() as f64;
        let runs_per_s = runs_f / time_s;

        println!("\n\nFinished in {}s, {} runs/s.", time_s, runs_per_s);

        let stats = results
            .iter()
            .map(TestStats::create)
            .fold(TestStats::new(), TestStats::combine);

        println!("\n{} runs, {} failures, {} errors, {} skips.", stats.runs, stats.failures, stats.errors, stats.skips);

        if stats.skips > 0 {
            println!("\nYou have skipped tests. Run with --verbose for details.");
        }
    }
}
<commit_msg>Move some printing logic into Display impls.<commit_after>extern crate time;

use std::fmt;

pub enum TestResult {
    Pass,
    Fail,
    Error,
    Skipped
}

impl fmt::Display for TestResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let rep = match *self {
            TestResult::Pass => ".",
            TestResult::Fail => "F",
            TestResult::Error => "E",
            TestResult::Skipped => "S"
        };
        write!(f, "{}", rep)
    }
}

pub trait Runnable {
    fn run(&self) -> TestResult;
}

struct TestTimings {
    time_s: f64,
    runs_per_s: f64
}

impl fmt::Display for TestTimings {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Finished in {}s, {} runs/s.", self.time_s, self.runs_per_s)
    }
}

struct TestStats {
    runs: usize,
    failures: usize,
    errors: usize,
    skips: usize,
}

impl TestStats {
    fn new() -> TestStats {
        TestStats {
            runs: 0,
            failures: 0,
            errors: 0,
            skips: 0
        }
    }

    fn create(result: &TestResult) -> TestStats {
        TestStats {
            runs: 1,
            failures: match *result { TestResult::Fail => 1, _ => 0 },
            errors: match *result { TestResult::Error => 1, _ => 0 },
            skips: match *result { TestResult::Skipped => 1, _ => 0 },
        }
    }

    fn combine(a: TestStats, b: TestStats) -> TestStats {
        TestStats {
            runs: a.runs + b.runs,
            failures: a.failures + b.failures,
            errors: a.errors + b.errors,
            skips: a.skips + b.skips
        }
    }
}

impl fmt::Display for TestStats {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} runs, {} failures, {} errors, {} skips.", self.runs, self.failures, self.errors, self.skips)
    }
}

pub struct TestRunner;

impl TestRunner {
    pub fn run(&self, tests: &Vec<Box<Runnable>>) {
        use std::io::{Write,stdout};

        println!("# Running.\n");

        let start_time = time::precise_time_ns();

        let mut results: Vec<TestResult>;

        {
            let out = stdout();
            let mut lock = out.lock();

            results = tests
                .iter()
                .map(|test| {
                    let result = test.run();
                    match write!(&mut lock, "{}", result) {
                        Ok(_) => match lock.flush() {
                            Ok(_) => {},
                            _ => panic!("Unable to flush test result")
                        },
                        _ => panic!("Unable to write test result")
                    };
                    result
                })
                .collect();
        }

        let end_time = time::precise_time_ns();
        let time_ms = end_time.wrapping_sub(start_time) as i64 / 1000000;
        let time_s = time_ms as f64 / 1000f64;
        let timings = TestTimings {
            time_s: time_s,
            runs_per_s: results.len() as f64 / time_s
        };

        println!("\n\n{}", timings);

        let stats = results
            .iter()
            .map(TestStats::create)
            .fold(TestStats::new(), TestStats::combine);

        println!("\n{}", stats);

        if stats.skips > 0 {
            println!("\nYou have skipped tests. Run with --verbose for details.");
        }
    }
}
<|endoftext|>


<commit_before>// XXX: Use a ref-counted gene Pool.
// A population is then only a collection of pool item ids.
// This prevents from duplicating potential large genes.

#![feature(num_bits_bytes)]
extern crate bit_vec;
extern crate rand;
extern crate simple_parallel;
use rand::{Rand, Rng};
use std::cmp::{PartialOrd, Ordering};
use simple_parallel::Pool;

pub mod bit_string;

/// A probability is a value in the range [0.0, 1.0].
/// A probability of 1.0 means `always`, that of 0.0
/// means `never`.
#[derive(Copy, Clone, Debug)]
pub struct Probability(f32);

impl Probability {
    #[inline]
    pub fn new(pb: f32) -> Probability {
        assert!(pb >= 0.0 && pb <= 1.0);
        Probability(pb)
    }
}

impl std::ops::Add<Probability> for Probability {
    type Output = Probability;
    #[inline]
    fn add(self, rhs: Probability) -> Probability {
        Probability::new(self.0 + rhs.0)
    }
}

/// A probability value is a random value in the
/// range [0.0, 1.0).
#[derive(Copy, Clone, Debug)]
pub struct ProbabilityValue(f32);

impl Rand for ProbabilityValue {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> ProbabilityValue {
        let val = rng.gen::<f32>();
        assert!(val >= 0.0 && val < 1.0);
        ProbabilityValue(val)
    }
}

impl ProbabilityValue {
    #[inline]
    pub fn is_probable_with(self, pb: Probability) -> bool {
        self.0 < pb.0
    }
}

/// Maximizes the fitness value as objective.
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct MaxFitness<T: PartialOrd + Clone + Send + Default>(pub T);

impl<T:PartialOrd+Send+Clone+Default> PartialOrd for MaxFitness<T> {
    #[inline]
    fn partial_cmp(&self, other: &MaxFitness<T>) -> Option<Ordering> {
        self.0.partial_cmp(&other.0).map(|i| i.reverse())
    }
}

/// Minimizes the fitness value as objective.
#[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)]
pub struct MinFitness<T: PartialOrd + Clone + Send + Default>(pub T);

/// Represents an individual in a Population.
pub trait Individual: Clone+Send {
}

/// Manages a population of (unrated) individuals.
#[derive(Clone, Debug)]
pub struct UnratedPopulation<I: Individual> {
    population: Vec<I>,
}

/// Manages a population of rated individuals.
#[derive(Clone, Debug)]
pub struct RatedPopulation<I: Individual, F> {
    rated_population: Vec<(I,F)>,
}

impl<I:Individual> UnratedPopulation<I> {

    pub fn new() -> UnratedPopulation<I> {
        UnratedPopulation { population: Vec::new() }
    }

    pub fn with_capacity(capa: usize) -> UnratedPopulation<I> {
        UnratedPopulation { population: Vec::with_capacity(capa) }
    }

    #[inline(always)]
    pub fn len(&self) -> usize {
        self.population.len()
    }

    #[inline]
    pub fn get(&self, idx: usize) -> &I {
        &self.population[idx]
    }

    pub fn add(&mut self, ind: I) {
        self.population.push(ind);
    }

    fn extend_with(&mut self, p: UnratedPopulation<I>) {
        self.population.extend(p.population);
    }

    /// Evaluates the whole population, i.e. determines the fitness of
    /// each `individual` (unless already calculated).
    /// Returns the rated population.
    pub fn rate<E, F>(self, evaluator: &E) -> RatedPopulation<I, F>
        where E: Evaluator<I, F>,
              F: PartialOrd+Clone+Send
    {
        let len = self.population.len();
        let rated_population : Vec<(I,F)> = self.population.into_iter().map(|ind| {
            let fitness = evaluator.fitness(&ind);
            (ind, fitness)
        }).collect();
        debug_assert!(rated_population.len() == len);
        RatedPopulation {rated_population: rated_population}
    }

    /// Evaluate the population in parallel using the threadpool `pool`.
    pub fn rate_in_parallel<E, F>(self, evaluator: &E, pool: &mut Pool, chunk_size: usize) -> RatedPopulation<I, F>
        where E: Evaluator<I, F>,
              F: PartialOrd+Clone+Send+Default,
    {
        let len = self.population.len();
        let mut rated_population : Vec<(I,F)> = self.population.into_iter().map(|ind| {
            let fitness = F::default();
            (ind, fitness)
        }).collect();

        pool.for_(rated_population.chunks_mut(chunk_size), |chunk| {
            for &mut (ref ind, ref mut fitness) in chunk.iter_mut() {
                *fitness = evaluator.fitness(ind);
            }
        });

        debug_assert!(rated_population.len() == len);
        RatedPopulation {rated_population: rated_population}
    }

}

impl<I:Individual, F:PartialOrd+Clone+Send+Default> RatedPopulation<I, F>
{
    pub fn new() -> RatedPopulation<I, F> {
        RatedPopulation { rated_population: Vec::new() }
    }

    pub fn with_capacity(capa: usize) -> RatedPopulation<I, F> {
        RatedPopulation { rated_population: Vec::with_capacity(capa) }
    }

    #[inline(always)]
    pub fn len(&self) -> usize {
        self.rated_population.len()
    }

    pub fn add(&mut self, ind: I, fitness: F) {
        self.rated_population.push((ind, fitness));
    }

    #[inline]
    pub fn get(&self, idx: usize) -> &I {
        &self.rated_population[idx].0
    }

    #[inline]
    pub fn get_individual(&self, idx: usize) -> &I {
        self.get(idx)
    }

    #[inline]
    pub fn get_fitness(&self, idx: usize) -> &F {
        &self.rated_population[idx].1
    }

    fn extend_with(&mut self, p: RatedPopulation<I, F>) {
        self.rated_population.extend(p.rated_population);
    }

    #[inline]
    pub fn fitter_than(&self, i1: usize, i2: usize) -> bool {
        self.get_fitness(i1) < self.get_fitness(i2)
    }

    /// Return index of individual with best fitness.
    pub fn fittest(&self) -> usize {
        assert!(self.len() > 0);
        let mut fittest = 0;

        for i in 1 .. self.rated_population.len() {
            if self.rated_population[i].1 < self.rated_population[fittest].1 {
                fittest = i;
            }
        }

        return fittest;
    }

}

/// Evaluates the fitness of an Individual.
pub trait Evaluator<I:Individual, F:PartialOrd+Clone+Send>: Sync {
    fn fitness(&self, individual: &I) -> F;
}

/// Select the best individual out of `k` randomly choosen.
/// This gives individuals with better fitness a higher chance to reproduce.
/// `n` is the total number of individuals.
///
/// NOTE: We are not using `sample(rng, 0..n, k)` as it is *very* expensive.
/// Instead we call `rng.gen_range()` k-times. The drawn items could be the same,
/// but the probability is very low if `n` is high compared to `k`.
#[inline]
pub fn tournament_selection_fast<R: Rng, F>(rng: &mut R,
                                          better_than: F,
                                          n: usize,
                                          k: usize)
                                          -> usize
    where F: Fn(usize, usize) -> bool
{
    assert!(n > 0);
    assert!(k > 0);
    assert!(n >= k);

    let mut best: usize = rng.gen_range(0, n);

    for _ in 1..k {
        let i = rng.gen_range(0, n);
        if better_than(i, best) {
            best = i;
        }
    }

    return best;
}

pub enum VariationMethod {
    Crossover,
    Mutation,
    Reproduction,
}

/// Mates two individual, producing one child.
pub trait OpCrossover1<I: Individual> {
    fn crossover1(&mut self, parent1: &I, parent2: &I) -> I;
}

/// Mates two individual, producing two children.
pub trait OpCrossover<I: Individual> {
    fn crossover(&mut self, parent1: &I, parent2: &I) -> (I, I);
}

/// Mutates an individual.
pub trait OpMutate<I: Individual> {
    fn mutate(&mut self, ind: &I) -> I;
}

/// Selects a variation method to use.
pub trait OpVariation {
    fn variation(&mut self) -> VariationMethod;
}

/// Selects a random individual from the population.
pub trait OpSelectRandomIndividual<I: Individual, F: PartialOrd> {
    fn select_random_individual<'a>(&mut self,
                                    population: &'a RatedPopulation<I, F>)
                                    -> usize; // IndividualIndex
}

/// Produce new generation through selection of \mu individuals from population.
pub trait OpSelect<I: Individual, F: PartialOrd> {
    fn select(&mut self, population: &RatedPopulation<I, F>, mu: usize) -> RatedPopulation<I, F>;
}

pub fn variation_or<I, F, T>(toolbox: &mut T,
                             population: &RatedPopulation<I, F>,
                             lambda: usize)
                             -> (UnratedPopulation<I>, RatedPopulation<I,F>)
    where I: Individual,
          F: PartialOrd+Clone+Send+Default,
          T: OpCrossover1<I> + OpMutate<I> + OpVariation + OpSelectRandomIndividual<I, F>
{
    // We assume that most offspring is unrated and only a small amount of already rated offspring.
    let mut unrated_offspring = UnratedPopulation::with_capacity(lambda);
    let mut rated_offspring = RatedPopulation::new();

    // Each step produces exactly one child.
    for _ in 0..lambda {
        let method = toolbox.variation();
        match method {
            VariationMethod::Crossover => {
                // select two individuals and mate them.
                // only the first offspring is used, the second is thrown away.
                let parent1_idx = toolbox.select_random_individual(population);
                let parent2_idx = toolbox.select_random_individual(population);
                let child1 = toolbox.crossover1(population.get(parent1_idx), population.get(parent2_idx));
                unrated_offspring.add(child1);
            }
            VariationMethod::Mutation => {
                // select a single individual and mutate it.
                let ind_idx = toolbox.select_random_individual(population);
                let child = toolbox.mutate(population.get(ind_idx));
                unrated_offspring.add(child);
            }
            VariationMethod::Reproduction => {
                let ind_idx = toolbox.select_random_individual(population);
                rated_offspring.add(population.get_individual(ind_idx).clone(), population.get_fitness(ind_idx).clone());
            }
        }
    }
    return (unrated_offspring, rated_offspring);
}

// The (\mu + \lambda) algorithm.
// From `population`, \lambda offspring is produced, through either
// mutation, crossover or random reproduction.
// For the next generation, \mu individuals are selected from the \mu + \lambda
// (parents and offspring).
#[inline]
pub fn ea_mu_plus_lambda<I,F,T,E,S>(toolbox: &mut T, evaluator: &E, mut population: RatedPopulation<I,F>, mu: usize, lambda: usize, num_generations: usize, stat: S, numthreads: usize, chunksize: usize)
    -> RatedPopulation<I,F>
where I: Individual,
      F: PartialOrd+Clone+Send+Default,
      T: OpCrossover1<I> + OpMutate<I> + OpVariation + OpSelectRandomIndividual<I,F> + OpSelect<I,F>,
      E: Evaluator<I,F>+Sync,
      S: Fn(usize, usize, &RatedPopulation<I,F>)
{
    let mut pool = simple_parallel::Pool::new(numthreads);

    //let nevals = population.rate_in_parallel(evaluator, &mut pool, chunksize);
    //stat(0, nevals, &population);

    for gen in 0..num_generations {
        // evaluate population. make sure that every individual has been rated.
        let (unrated_offspring, rated_offspring) = variation_or(toolbox, &population, lambda);
        let nevals = unrated_offspring.len();
        population.extend_with(rated_offspring);
        population.extend_with(unrated_offspring.rate_in_parallel(evaluator, &mut pool, chunksize));

        // select from offspring the `best` individuals
        let p = toolbox.select(&population, mu);
        stat(gen + 1, nevals, &p);
        population = p;
    }

    return population;
}
<commit_msg>Reduce required trait specification<commit_after>// XXX: Use a ref-counted gene Pool.
// A population is then only a collection of pool item ids.
// This prevents from duplicating potential large genes.

#![feature(num_bits_bytes)]
extern crate bit_vec;
extern crate rand;
extern crate simple_parallel;
use rand::{Rand, Rng};
use std::cmp::{PartialOrd, Ordering};
use simple_parallel::Pool;

pub mod bit_string;

/// A probability is a value in the range [0.0, 1.0].
/// A probability of 1.0 means `always`, that of 0.0
/// means `never`.
#[derive(Copy, Clone, Debug)]
pub struct Probability(f32);

impl Probability {
    #[inline]
    pub fn new(pb: f32) -> Probability {
        assert!(pb >= 0.0 && pb <= 1.0);
        Probability(pb)
    }
}

impl std::ops::Add<Probability> for Probability {
    type Output = Probability;
    #[inline]
    fn add(self, rhs: Probability) -> Probability {
        Probability::new(self.0 + rhs.0)
    }
}

/// A probability value is a random value in the
/// range [0.0, 1.0).
#[derive(Copy, Clone, Debug)]
pub struct ProbabilityValue(f32);

impl Rand for ProbabilityValue {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> ProbabilityValue {
        let val = rng.gen::<f32>();
        assert!(val >= 0.0 && val < 1.0);
        ProbabilityValue(val)
    }
}

impl ProbabilityValue {
    #[inline]
    pub fn is_probable_with(self, pb: Probability) -> bool {
        self.0 < pb.0
    }
}

/// Maximizes the fitness value as objective.
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct MaxFitness<T: PartialOrd + Clone + Send + Default>(pub T);

impl<T:PartialOrd+Send+Clone+Default> PartialOrd for MaxFitness<T> {
    #[inline]
    fn partial_cmp(&self, other: &MaxFitness<T>) -> Option<Ordering> {
        self.0.partial_cmp(&other.0).map(|i| i.reverse())
    }
}

/// Minimizes the fitness value as objective.
#[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)]
pub struct MinFitness<T: PartialOrd + Clone + Send + Default>(pub T);

/// Represents an individual in a Population.
pub trait Individual: Clone+Send {
}

/// Manages a population of (unrated) individuals.
#[derive(Clone, Debug)]
pub struct UnratedPopulation<I: Individual> {
    population: Vec<I>,
}

/// Manages a population of rated individuals.
#[derive(Clone, Debug)]
pub struct RatedPopulation<I: Individual, F:PartialOrd> {
    rated_population: Vec<(I,F)>,
}

impl<I:Individual> UnratedPopulation<I> {

    pub fn new() -> UnratedPopulation<I> {
        UnratedPopulation { population: Vec::new() }
    }

    pub fn with_capacity(capa: usize) -> UnratedPopulation<I> {
        UnratedPopulation { population: Vec::with_capacity(capa) }
    }

    #[inline(always)]
    pub fn len(&self) -> usize {
        self.population.len()
    }

    #[inline]
    pub fn get(&self, idx: usize) -> &I {
        &self.population[idx]
    }

    pub fn add(&mut self, ind: I) {
        self.population.push(ind);
    }

    fn extend_with(&mut self, p: UnratedPopulation<I>) {
        self.population.extend(p.population);
    }

    /// Evaluates the whole population, i.e. determines the fitness of
    /// each `individual` (unless already calculated).
    /// Returns the rated population.
    pub fn rate<E, F>(self, evaluator: &E) -> RatedPopulation<I, F>
        where E: Evaluator<I, F>,
              F: PartialOrd
    {
        let len = self.population.len();
        let rated_population : Vec<(I,F)> = self.population.into_iter().map(|ind| {
            let fitness = evaluator.fitness(&ind);
            (ind, fitness)
        }).collect();
        debug_assert!(rated_population.len() == len);
        RatedPopulation {rated_population: rated_population}
    }

    /// Evaluate the population in parallel using the threadpool `pool`.
    pub fn rate_in_parallel<E, F>(self, evaluator: &E, pool: &mut Pool, chunk_size: usize) -> RatedPopulation<I, F>
        where E: Evaluator<I, F>,
              F: PartialOrd+Send+Default,
    {
        let len = self.population.len();
        let mut rated_population : Vec<(I,F)> = self.population.into_iter().map(|ind| {
            let fitness = F::default();
            (ind, fitness)
        }).collect();

        pool.for_(rated_population.chunks_mut(chunk_size), |chunk| {
            for &mut (ref ind, ref mut fitness) in chunk.iter_mut() {
                *fitness = evaluator.fitness(ind);
            }
        });

        debug_assert!(rated_population.len() == len);
        RatedPopulation {rated_population: rated_population}
    }

}

impl<I:Individual, F:PartialOrd> RatedPopulation<I, F>
{
    pub fn new() -> RatedPopulation<I, F> {
        RatedPopulation { rated_population: Vec::new() }
    }

    pub fn with_capacity(capa: usize) -> RatedPopulation<I, F> {
        RatedPopulation { rated_population: Vec::with_capacity(capa) }
    }

    #[inline(always)]
    pub fn len(&self) -> usize {
        self.rated_population.len()
    }

    pub fn add(&mut self, ind: I, fitness: F) {
        self.rated_population.push((ind, fitness));
    }

    #[inline]
    pub fn get(&self, idx: usize) -> &I {
        &self.rated_population[idx].0
    }

    #[inline]
    pub fn get_individual(&self, idx: usize) -> &I {
        self.get(idx)
    }

    #[inline]
    pub fn get_fitness(&self, idx: usize) -> &F {
        &self.rated_population[idx].1
    }

    fn extend_with(&mut self, p: RatedPopulation<I, F>) {
        self.rated_population.extend(p.rated_population);
    }

    #[inline]
    pub fn fitter_than(&self, i1: usize, i2: usize) -> bool {
        self.get_fitness(i1) < self.get_fitness(i2)
    }

    /// Return index of individual with best fitness.
    pub fn fittest(&self) -> usize {
        assert!(self.len() > 0);
        let mut fittest = 0;

        for i in 1 .. self.rated_population.len() {
            if self.rated_population[i].1 < self.rated_population[fittest].1 {
                fittest = i;
            }
        }

        return fittest;
    }

}

/// Evaluates the fitness of an Individual.
pub trait Evaluator<I:Individual, F:PartialOrd>: Sync {
    fn fitness(&self, individual: &I) -> F;
}

/// Select the best individual out of `k` randomly choosen.
/// This gives individuals with better fitness a higher chance to reproduce.
/// `n` is the total number of individuals.
///
/// NOTE: We are not using `sample(rng, 0..n, k)` as it is *very* expensive.
/// Instead we call `rng.gen_range()` k-times. The drawn items could be the same,
/// but the probability is very low if `n` is high compared to `k`.
#[inline]
pub fn tournament_selection_fast<R: Rng, F>(rng: &mut R,
                                          better_than: F,
                                          n: usize,
                                          k: usize)
                                          -> usize
    where F: Fn(usize, usize) -> bool
{
    assert!(n > 0);
    assert!(k > 0);
    assert!(n >= k);

    let mut best: usize = rng.gen_range(0, n);

    for _ in 1..k {
        let i = rng.gen_range(0, n);
        if better_than(i, best) {
            best = i;
        }
    }

    return best;
}

pub enum VariationMethod {
    Crossover,
    Mutation,
    Reproduction,
}

/// Mates two individual, producing one child.
pub trait OpCrossover1<I: Individual> {
    fn crossover1(&mut self, parent1: &I, parent2: &I) -> I;
}

/// Mates two individual, producing two children.
pub trait OpCrossover<I: Individual> {
    fn crossover(&mut self, parent1: &I, parent2: &I) -> (I, I);
}

/// Mutates an individual.
pub trait OpMutate<I: Individual> {
    fn mutate(&mut self, ind: &I) -> I;
}

/// Selects a variation method to use.
pub trait OpVariation {
    fn variation(&mut self) -> VariationMethod;
}

/// Selects a random individual from the population.
pub trait OpSelectRandomIndividual<I: Individual, F: PartialOrd> {
    fn select_random_individual<'a>(&mut self,
                                    population: &'a RatedPopulation<I, F>)
                                    -> usize; // IndividualIndex
}

/// Produce new generation through selection of \mu individuals from population.
pub trait OpSelect<I: Individual, F: PartialOrd> {
    fn select(&mut self, population: &RatedPopulation<I, F>, mu: usize) -> RatedPopulation<I, F>;
}

pub fn variation_or<I, F, T>(toolbox: &mut T,
                             population: &RatedPopulation<I, F>,
                             lambda: usize)
                             -> (UnratedPopulation<I>, RatedPopulation<I,F>)
    where I: Individual,
          F: PartialOrd+Clone,
          T: OpCrossover1<I> + OpMutate<I> + OpVariation + OpSelectRandomIndividual<I, F>
{
    // We assume that most offspring is unrated and only a small amount of already rated offspring.
    let mut unrated_offspring = UnratedPopulation::with_capacity(lambda);
    let mut rated_offspring = RatedPopulation::new();

    // Each step produces exactly one child.
    for _ in 0..lambda {
        let method = toolbox.variation();
        match method {
            VariationMethod::Crossover => {
                // select two individuals and mate them.
                // only the first offspring is used, the second is thrown away.
                let parent1_idx = toolbox.select_random_individual(population);
                let parent2_idx = toolbox.select_random_individual(population);
                let child1 = toolbox.crossover1(population.get(parent1_idx), population.get(parent2_idx));
                unrated_offspring.add(child1);
            }
            VariationMethod::Mutation => {
                // select a single individual and mutate it.
                let ind_idx = toolbox.select_random_individual(population);
                let child = toolbox.mutate(population.get(ind_idx));
                unrated_offspring.add(child);
            }
            VariationMethod::Reproduction => {
                let ind_idx = toolbox.select_random_individual(population);
                rated_offspring.add(population.get_individual(ind_idx).clone(), population.get_fitness(ind_idx).clone());
            }
        }
    }
    return (unrated_offspring, rated_offspring);
}

// The (\mu + \lambda) algorithm.
// From `population`, \lambda offspring is produced, through either
// mutation, crossover or random reproduction.
// For the next generation, \mu individuals are selected from the \mu + \lambda
// (parents and offspring).
#[inline]
pub fn ea_mu_plus_lambda<I,F,T,E,S>(toolbox: &mut T, evaluator: &E, mut population: RatedPopulation<I,F>, mu: usize, lambda: usize, num_generations: usize, stat: S, numthreads: usize, chunksize: usize)
    -> RatedPopulation<I,F>
where I: Individual,
      F: PartialOrd+Clone+Send+Default,
      T: OpCrossover1<I> + OpMutate<I> + OpVariation + OpSelectRandomIndividual<I,F> + OpSelect<I,F>,
      E: Evaluator<I,F>+Sync,
      S: Fn(usize, usize, &RatedPopulation<I,F>)
{
    let mut pool = simple_parallel::Pool::new(numthreads);

    //let nevals = population.rate_in_parallel(evaluator, &mut pool, chunksize);
    //stat(0, nevals, &population);

    for gen in 0..num_generations {
        // evaluate population. make sure that every individual has been rated.
        let (unrated_offspring, rated_offspring) = variation_or(toolbox, &population, lambda);
        let nevals = unrated_offspring.len();
        population.extend_with(rated_offspring);
        population.extend_with(unrated_offspring.rate_in_parallel(evaluator, &mut pool, chunksize));

        // select from offspring the `best` individuals
        let p = toolbox.select(&population, mu);
        stat(gen + 1, nevals, &p);
        population = p;
    }

    return population;
}
<|endoftext|>