<commit_before>use std::cmp::Ord;

use math;
use platform::Element;
use schedule::{Decision, Schedule, Queue};
use system::Job;
use {Config, Result};

/// A first-in-first-served scheduling policy.
pub struct Impartial {
    elements: Vec<Element>,
    queues: Vec<Queue>,
}

impl Impartial {
    /// Create a scheduling policy.
    pub fn new(_: &Config, elements: &[Element]) -> Result<Impartial> {
        Ok(Impartial {
            elements: elements.to_vec(),
            queues: elements.iter().map(|element| Queue::new(element.capacity())).collect(),
        })
    }
}

impl Schedule for Impartial {
    fn push(&mut self, job: &Job) -> Result<Decision> {
        let hosts = &self.elements;
        let guests = &job.elements;
        let (have, need) = (hosts.len(), guests.len());

        let mut start = job.arrival;
        let length = job.duration();

        'outer: loop {
            let intervals = self.queues.iter().map(|queue| queue.next(start, length))
                                              .collect::<Vec<_>>();

            let order = sort(&intervals);
            start = intervals[order[0]].start();

            let mut found = vec![None; need];
            let mut taken = vec![false; have];

            'inner: for i in 0..need {
                for &j in &order {
                    if taken[j] || intervals[j].start() != start {
                        continue;
                    }
                    if guests[i].accept(&hosts[j]) {
                        found[i] = Some(j);
                        taken[j] = true;
                        continue 'inner;
                    }
                }
                for &j in &order[1..] {
                    if intervals[j].start() > start {
                        start = intervals[j].start();
                        continue 'outer;
                    }
                }
                raise!("failed to allocated resouces for a job");
            }

            start = start.max(math::next_after(job.arrival));
            let finish = start + length;
            let mut mapping = Vec::with_capacity(need);
            for i in 0..need {
                let j = some!(found[i]);
                self.queues[j].push((start, finish));
                mapping.push((i, hosts[j].id));
            }

            return Ok(Decision::new(start, finish, mapping));
        }
    }

    fn tick(&mut self, time: f64) -> Result<()> {
        for queue in &mut self.queues {
            queue.tick(time);
        }
        Ok(())
    }
}

fn sort<T: Ord>(items: &[T]) -> Vec<usize> {
    let mut items = items.iter().enumerate().collect::<Vec<_>>();
    items.sort_by(|one, other| one.1.cmp(&other.1));
    items.iter().map(|item| item.0).collect()
}
<commit_msg>Fix a typo<commit_after>use std::cmp::Ord;

use math;
use platform::Element;
use schedule::{Decision, Schedule, Queue};
use system::Job;
use {Config, Result};

/// A first-in-first-served scheduling policy.
pub struct Impartial {
    elements: Vec<Element>,
    queues: Vec<Queue>,
}

impl Impartial {
    /// Create a scheduling policy.
    pub fn new(_: &Config, elements: &[Element]) -> Result<Impartial> {
        Ok(Impartial {
            elements: elements.to_vec(),
            queues: elements.iter().map(|element| Queue::new(element.capacity())).collect(),
        })
    }
}

impl Schedule for Impartial {
    fn push(&mut self, job: &Job) -> Result<Decision> {
        let hosts = &self.elements;
        let guests = &job.elements;
        let (have, need) = (hosts.len(), guests.len());

        let mut start = job.arrival;
        let length = job.duration();

        'outer: loop {
            let intervals = self.queues.iter().map(|queue| queue.next(start, length))
                                              .collect::<Vec<_>>();

            let order = sort(&intervals);
            start = intervals[order[0]].start();

            let mut found = vec![None; need];
            let mut taken = vec![false; have];

            'inner: for i in 0..need {
                for &j in &order {
                    if taken[j] || intervals[j].start() != start {
                        continue;
                    }
                    if guests[i].accept(&hosts[j]) {
                        found[i] = Some(j);
                        taken[j] = true;
                        continue 'inner;
                    }
                }
                for &j in &order[1..] {
                    if intervals[j].start() > start {
                        start = intervals[j].start();
                        continue 'outer;
                    }
                }
                raise!("failed to allocated resources for a job");
            }

            start = start.max(math::next_after(job.arrival));
            let finish = start + length;
            let mut mapping = Vec::with_capacity(need);
            for i in 0..need {
                let j = some!(found[i]);
                self.queues[j].push((start, finish));
                mapping.push((i, hosts[j].id));
            }

            return Ok(Decision::new(start, finish, mapping));
        }
    }

    fn tick(&mut self, time: f64) -> Result<()> {
        for queue in &mut self.queues {
            queue.tick(time);
        }
        Ok(())
    }
}

fn sort<T: Ord>(items: &[T]) -> Vec<usize> {
    let mut items = items.iter().enumerate().collect::<Vec<_>>();
    items.sort_by(|one, other| one.1.cmp(&other.1));
    items.iter().map(|item| item.0).collect()
}
<|endoftext|>


<commit_before>use std::env;
use std::thread;
use std::collections::HashMap;
use std::process::Command;

use http::app::App;

const DEFAULT_APP_HOME: &'static str = "~/.zas";

pub struct AppManager {
    pub next_port: u16,
    pub apps: HashMap<String, App>,
}

impl AppManager {
    pub fn new() -> AppManager {
        AppManager {
            next_port: 12050,
            apps: HashMap::new(),
        }
    }

    pub fn ensure_app_running(&mut self, app_name: &String) -> u16 {
        let app_home = env::var("ZAS_HOME").unwrap_or(DEFAULT_APP_HOME.to_string());

        if !self.apps.contains_key(app_name) {
            let next_port = self.next_port;
            self.apps.insert(app_name.to_string(), App::new(app_name.to_string(), next_port, &app_home));
            self.next_port = next_port + 1;

            block_until_port_open(next_port);
        }

        let app = self.apps.get(app_name).unwrap();

        app.port
    }
}

fn block_until_port_open(port: u16) {
    while !Command::new("nc").arg("-z").arg("localhost").arg(format!("{}", port)).status().unwrap().success() {
        thread::sleep_ms(300);
    }
}
<commit_msg>refactor: Avoid reading app_home on each request<commit_after>use std::env;
use std::thread;
use std::collections::HashMap;
use std::process::Command;

use http::app::App;

const DEFAULT_APP_HOME: &'static str = "~/.zas";

pub struct AppManager {
    pub next_port: u16,
    app_home: String,
    pub apps: HashMap<String, App>,
}

impl AppManager {
    pub fn new() -> AppManager {
        let app_home = env::var("ZAS_HOME").unwrap_or(DEFAULT_APP_HOME.to_string());

        AppManager {
            next_port: 12050,
            app_home: app_home,
            apps: HashMap::new(),
        }
    }

    pub fn ensure_app_running(&mut self, app_name: &String) -> u16 {
        if !self.apps.contains_key(app_name) {
            let next_port = self.next_port;
            self.apps.insert(app_name.to_string(), App::new(app_name.to_string(), next_port, &self.app_home));
            self.next_port = next_port + 1;

            block_until_port_open(next_port);
        }

        let app = self.apps.get(app_name).unwrap();

        app.port
    }
}

fn block_until_port_open(port: u16) {
    while !Command::new("nc").arg("-z").arg("localhost").arg(format!("{}", port)).status().unwrap().success() {
        thread::sleep_ms(300);
    }
}
<|endoftext|>


<commit_before>use std::str::Chars;
use std::iter::Peekable;
use std::iter::Enumerate;

use ::syntax::lexer::{Token, Lexer, Span};
use ::syntax::next_is;

pub struct RustSyntax;

impl Lexer for RustSyntax {
    fn handle_char(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize, idx: usize) -> Option<Span> {
        match ch {
            '#' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '!') || next_is(&mut iter, '[') {
                    let mut s = String::from("#");
                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::Attribute(s),
                    });
                }
                return Some(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Hash})
            }

            '/' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '/') {
                    let mut s = String::from("/");
                    s.push(iter.next().unwrap().1);

                    let mut doc_comment = false;
                    if next_is(&mut iter, '/') {
                        doc_comment = true;
                    }

                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }

                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: if doc_comment{ Token::DocComment(s) } else { Token::SingleLineComment(s) },
                    });
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::ForwardSlash,
                });
            }

            '"' => {
                let st = idx;
                let mut end = idx;
                let mut s = String::from("\"");
                while let Some(&(e, c)) = iter.peek() {
                    end = e;
                    s.push(iter.next().unwrap().1);
                    if c == '"' {
                        break;
                    }
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::String(s),
                });
            }

            '\'' => {
                let st = idx;
                let mut end = idx;
                let mut s = String::from("\'");
                while let Some(&(e, c)) = iter.peek() {
                    end = e;
                    s.push(iter.next().unwrap().1);
                    if c == '\\' {
                        if let Some(&(e, c_)) = iter.peek() {
                            // this is handling escaped single quotes...
                            if c_ == '\'' {
                                s.push(iter.next().unwrap().1);
                                continue;
                            }
                        }
                    }
                    if c == '\'' {
                        break;
                    }
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::Special(s),
                });
            }

            ':' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, ':') {
                    let (e, c) = iter.next().unwrap();
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: e,
                        token: Token::Special(String::from("::")),
                    });
                } else {
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::Colon,
                    });
                }
            }

            _ => None,
        }

    }

    fn handle_ident(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize) -> Span {
        let mut ident = String::new();
        ident.push(ch);
        let start = iter.peek().unwrap().0 - 1;

        while self.is_ident(iter.peek()) {
            ident.push(iter.next().unwrap().1)
        }

        Span {
            y_pos: y_pos,
            start: start,
            end: start + ident.len() - 1,
            token: Token::Ident(ident),
        }
    }
}

<commit_msg>Fix rendering escaped strings in rust<commit_after>use std::str::Chars;
use std::iter::Peekable;
use std::iter::Enumerate;

use ::syntax::lexer::{Token, Lexer, Span};
use ::syntax::next_is;

pub struct RustSyntax;

impl Lexer for RustSyntax {
    fn handle_char(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize, idx: usize) -> Option<Span> {
        match ch {
            '#' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '!') || next_is(&mut iter, '[') {
                    let mut s = String::from("#");
                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::Attribute(s),
                    });
                }
                return Some(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Hash})
            }

            '/' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '/') {
                    let mut s = String::from("/");
                    s.push(iter.next().unwrap().1);

                    let mut doc_comment = false;
                    if next_is(&mut iter, '/') {
                        doc_comment = true;
                    }

                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }

                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: if doc_comment{ Token::DocComment(s) } else { Token::SingleLineComment(s) },
                    });
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::ForwardSlash,
                });
            }

            '"' => {
                let st = idx;
                let mut end = idx;
                let mut s = String::from("\"");
                while let Some(&(e, c)) = iter.peek() {
                    end = e;
                    s.push(iter.next().unwrap().1);
                    if c == '\\' {
                        if let Some(&(e, c_)) = iter.peek() {
                            // this is handling escaped single quotes...
                            if c_ == '"' {
                                s.push(iter.next().unwrap().1);
                                continue;
                            }
                        }
                    }
                    if c == '"' {
                        break;
                    }
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::String(s),
                });
            }

            '\'' => {
                let st = idx;
                let mut end = idx;
                let mut s = String::from("\'");
                while let Some(&(e, c)) = iter.peek() {
                    end = e;
                    s.push(iter.next().unwrap().1);
                    if c == '\\' {
                        if let Some(&(e, c_)) = iter.peek() {
                            // this is handling escaped single quotes...
                            if c_ == '\'' {
                                s.push(iter.next().unwrap().1);
                                continue;
                            }
                        }
                    }
                    if c == '\'' {
                        break;
                    }
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::Special(s),
                });
            }

            ':' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, ':') {
                    let (e, c) = iter.next().unwrap();
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: e,
                        token: Token::Special(String::from("::")),
                    });
                } else {
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::Colon,
                    });
                }
            }

            _ => None,
        }

    }

    fn handle_ident(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize) -> Span {
        let mut ident = String::new();
        ident.push(ch);
        let start = iter.peek().unwrap().0 - 1;

        while self.is_ident(iter.peek()) {
            ident.push(iter.next().unwrap().1)
        }

        Span {
            y_pos: y_pos,
            start: start,
            end: start + ident.len() - 1,
            token: Token::Ident(ident),
        }
    }
}

<|endoftext|>


<commit_before>use crate::Msg;
use seed::prelude::*;

pub fn render() -> Node<Msg> {
    div![
        h1!["News"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "text"},
            tbody![
                tr![
                    //TODO: change this to styles
                    td![attrs!{At::Width => "100"},"Date"],
                    td![attrs!{At::Width => "300"},"News"],
                ],
                tr![
                    td!["26th June 2021"],
                    td![El::from_html("bigprimes.net is now using the trunk test server rather than node.")],
                ],
                tr![
                    td!["28th July 2019"],
                    td![El::from_html("bigprimes.net has been rewritten from the ground up using rust!
All archives have been retired in favour of client side processing in web assembly.")],
                ],
                tr![
                    td!["28th July 2019"],
                    td![El::from_html("Shout out to Gavin, who took the time to memorise all the news entries on the website!")],
                ],
                tr![
                    td!["22nd January 2019"],
                    td![El::from_html("Ethereum bounty contracts have now been added for anyone that would like to try to push the boundaries of human knowledge. The first contract is a competition for the correct solution to a³+b³+c³ = 33. Tweet me if you need assistance using these contracts!")],
                ],
                tr![
                    td!["10th March 2018"],
                    td![El::from_html("Added torrents for the first million primes and first billion prime numbers.")],
                ],
                tr![
                    td!["12th November 2017"],
                    td![El::from_html("Site is now running on AWS Lambda, but can still fallback to regular VM hosting if ever needed. Site is now ~40% covered by unit tests.")],
                ],
                tr![
                    td!["13th November 2016"],
                    td![El::from_html("Site source code has been converted to PHP7 with Silex framework. Some methods have also been moved to cpp from PHP https://github.com/craigmayhew/bigprimes.net/")],
                ],
                tr![
                    td!["28th February 2014"],
                    td![El::from_html("You can now find the websites php source code here https://github.com/craigmayhew/bigprimes.net/")],
                ],
                tr![
                    td!["19th November 2011"],
                    td![El::from_html("Thank you to Yu Kwong Yiu Wilson for the donation!")],
                ],
                tr![
                    td!["13th July 2011"],
                    td![El::from_html("We are retiring the distributed computing client. Thank you all for your help and processing cycles.
        Watch this space for an open source GPU client coming soon...")],
                ],
                tr![
                    td!["10th February 2010"],
                    td![El::from_html("We have added a page that shows the sum of the digits of prime numbers (now retired).")],
                ],
                tr![
                    td!["1st February 2010"],
                    td![El::from_html("Thanks to everyone for donating computer time, we are now upto 1.4 billion primes. We now also have a facebook group where you get news updates and show your support for the project!")],
                ],
                tr![
                    td!["28th September 2009"],
                    td![El::from_html("Thanks for all your help! We made it to one billion prime numbers! Please keep on donating processor time as we still have plenty of storage for the prime numbers. Our database is now more than double the size (300 million primes) and we've put in the capacity to keep growing. To view our current progress please visit the status page.")],
                ],
                tr![
                    td!["18th August 2009"],
                    td![El::from_html("It's been a while but we have been very busy. We've put together a distributed computing client written in javascript. Our database is now more than double the size (300 million primes) and we've put in the capacity to keep growing. To view our current progress please visit the status page.")],
                ],
                tr![
                    td!["17th July 2008"],
                    td![El::from_html("We've now added a Forum (now retired) which can be found on the navigation links on the left.")],
                ],
                tr![
                    td!["14th July 2008"],
                    td![El::from_html("Someone named Kirk just emailed me to say the download links wern't working. I've now fixed this. Thanks Kirk!")],
                ],
                tr![
                    td!["4th July 2008"],
                    td![El::from_html("Added much faster code to the cruncher so that we can handle more of your page loads! Lots of little updates and some reorganizing of the site.")],
                ],
                tr![
                    td!["23rd June 2007"],
                    td![El::from_html("Added the Downloads section.")],
                ],
                tr![
                    td!["11th February 2007"],
                    td![El::from_html("Added the Fibonacci number archive containing the first 70331 Fibonacci numbers.")],
                ],
                tr![
                    td!["16th January 2007"],
                    td![El::from_html("Added the 44th Mersenne Prime number to the archive.")],
                ],
                tr![
                    td!["12th January 2007"],
                    td![El::from_html("The Archives are now more organized.")],
                ],
                tr![
                    td!["28th September 2005"],
                    td![El::from_html("We have managed to archive the first 100 million prime numbers.")],
                ],
                tr![
                    td!["20th May 2005"],
                    td![El::from_html("We have managed to archive the first 75 million prime numbers.")],
                ],
                tr![
                    td!["16th May 2005"],
                    td![El::from_html("We have managed to archive the first 50 million prime numbers.")],
                ],
                tr![
                    td!["14th May 2005"],
                    td![El::from_html("We have managed to archive the first 10 million prime numbers.")],
                ],
                tr![
                    td!["13th May 2005"],
                    td![El::from_html("We have managed to archive the first 1 million prime numbers.")],
                ],
            ],
        ],
    ]
}
<commit_msg>Improved latest new entry to describe trunk<commit_after>use crate::Msg;
use seed::prelude::*;

pub fn render() -> Node<Msg> {
    div![
        h1!["News"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "text"},
            tbody![
                tr![
                    //TODO: change this to styles
                    td![attrs!{At::Width => "100"},"Date"],
                    td![attrs!{At::Width => "300"},"News"],
                ],
                tr![
                    td!["26th June 2021"],
                    td![El::from_html("bigprimes.net is now using the trunk WASM web application bundler for Rust.")],
                ],
                tr![
                    td!["28th July 2019"],
                    td![El::from_html("bigprimes.net has been rewritten from the ground up using rust!
All archives have been retired in favour of client side processing in web assembly.")],
                ],
                tr![
                    td!["28th July 2019"],
                    td![El::from_html("Shout out to Gavin, who took the time to memorise all the news entries on the website!")],
                ],
                tr![
                    td!["22nd January 2019"],
                    td![El::from_html("Ethereum bounty contracts have now been added for anyone that would like to try to push the boundaries of human knowledge. The first contract is a competition for the correct solution to a³+b³+c³ = 33. Tweet me if you need assistance using these contracts!")],
                ],
                tr![
                    td!["10th March 2018"],
                    td![El::from_html("Added torrents for the first million primes and first billion prime numbers.")],
                ],
                tr![
                    td!["12th November 2017"],
                    td![El::from_html("Site is now running on AWS Lambda, but can still fallback to regular VM hosting if ever needed. Site is now ~40% covered by unit tests.")],
                ],
                tr![
                    td!["13th November 2016"],
                    td![El::from_html("Site source code has been converted to PHP7 with Silex framework. Some methods have also been moved to cpp from PHP https://github.com/craigmayhew/bigprimes.net/")],
                ],
                tr![
                    td!["28th February 2014"],
                    td![El::from_html("You can now find the websites php source code here https://github.com/craigmayhew/bigprimes.net/")],
                ],
                tr![
                    td!["19th November 2011"],
                    td![El::from_html("Thank you to Yu Kwong Yiu Wilson for the donation!")],
                ],
                tr![
                    td!["13th July 2011"],
                    td![El::from_html("We are retiring the distributed computing client. Thank you all for your help and processing cycles.
        Watch this space for an open source GPU client coming soon...")],
                ],
                tr![
                    td!["10th February 2010"],
                    td![El::from_html("We have added a page that shows the sum of the digits of prime numbers (now retired).")],
                ],
                tr![
                    td!["1st February 2010"],
                    td![El::from_html("Thanks to everyone for donating computer time, we are now upto 1.4 billion primes. We now also have a facebook group where you get news updates and show your support for the project!")],
                ],
                tr![
                    td!["28th September 2009"],
                    td![El::from_html("Thanks for all your help! We made it to one billion prime numbers! Please keep on donating processor time as we still have plenty of storage for the prime numbers. Our database is now more than double the size (300 million primes) and we've put in the capacity to keep growing. To view our current progress please visit the status page.")],
                ],
                tr![
                    td!["18th August 2009"],
                    td![El::from_html("It's been a while but we have been very busy. We've put together a distributed computing client written in javascript. Our database is now more than double the size (300 million primes) and we've put in the capacity to keep growing. To view our current progress please visit the status page.")],
                ],
                tr![
                    td!["17th July 2008"],
                    td![El::from_html("We've now added a Forum (now retired) which can be found on the navigation links on the left.")],
                ],
                tr![
                    td!["14th July 2008"],
                    td![El::from_html("Someone named Kirk just emailed me to say the download links wern't working. I've now fixed this. Thanks Kirk!")],
                ],
                tr![
                    td!["4th July 2008"],
                    td![El::from_html("Added much faster code to the cruncher so that we can handle more of your page loads! Lots of little updates and some reorganizing of the site.")],
                ],
                tr![
                    td!["23rd June 2007"],
                    td![El::from_html("Added the Downloads section.")],
                ],
                tr![
                    td!["11th February 2007"],
                    td![El::from_html("Added the Fibonacci number archive containing the first 70331 Fibonacci numbers.")],
                ],
                tr![
                    td!["16th January 2007"],
                    td![El::from_html("Added the 44th Mersenne Prime number to the archive.")],
                ],
                tr![
                    td!["12th January 2007"],
                    td![El::from_html("The Archives are now more organized.")],
                ],
                tr![
                    td!["28th September 2005"],
                    td![El::from_html("We have managed to archive the first 100 million prime numbers.")],
                ],
                tr![
                    td!["20th May 2005"],
                    td![El::from_html("We have managed to archive the first 75 million prime numbers.")],
                ],
                tr![
                    td!["16th May 2005"],
                    td![El::from_html("We have managed to archive the first 50 million prime numbers.")],
                ],
                tr![
                    td!["14th May 2005"],
                    td![El::from_html("We have managed to archive the first 10 million prime numbers.")],
                ],
                tr![
                    td!["13th May 2005"],
                    td![El::from_html("We have managed to archive the first 1 million prime numbers.")],
                ],
            ],
        ],
    ]
}
<|endoftext|>


<commit_before>//! The parser module is responsible for parsing FITS files.

use std::str;
use std::str::FromStr;
use super::types::{Keyword, BlankRecord};

named!(fits<&[u8], ((Vec<Keyword>, Keyword, Vec<BlankRecord>), Vec<&[u8]>) >,
       pair!(primary_header, many0!( take!(2880) )));

named!(primary_header<&[u8], (Vec<Keyword>, Keyword, Vec<BlankRecord>)>,
       tuple!(
           many0!(keyword_record),
           end_record,
           many0!(blank_record)
       ));

named!(keyword_record<&[u8], Keyword>,
       map_res!( // TODO should use map_res!
           map!(
               tuple!(
                   take!(8),
                   tag!("="),
                   take!(71)
               ), |(slice, _, _) : (&[u8], &[u8], &[u8])| {
                   "OBJECT" // TODO obviously wrong, correct it
               }),
           Keyword::from_str));

named!(keyword<&[u8], Keyword>,
       map_res!(
           map_res!(
               take!(8),
               str::from_utf8),
           Keyword::from_str
       ));

named!(end_record<&[u8], Keyword>,
       map!(
           pair!(tag!("END"), count!(tag!(" "), 77)),
           |_| { Keyword::END }
       ));

named!(blank_record<&[u8], BlankRecord>,
       map!(
           count!(tag!(" "), 80),
           |_| { BlankRecord }
       ));

#[cfg(test)]
mod tests {
    use nom::{IResult};
    use super::super::types::{Keyword, BlankRecord};
    use super::{fits, primary_header, keyword_record, keyword, end_record, blank_record};

    #[test]
    fn it_should_parse_a_fits_file(){
        let data = include_bytes!("../../assets/images/k2-trappist1-unofficial-tpf-long-cadence.fits");

        let result = fits(data);

        match result {
            IResult::Done(_, (header, blocks)) => {
                assert_eq!(blocks.len(), 3675);
            },
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn primary_header_should_parse_a_primary_header(){
        let data = include_bytes!("../../assets/images/k2-trappist1-unofficial-tpf-long-cadence.fits");

        let result = primary_header(&data[0..(2*2880)]);

        match result {
            IResult::Done(_, (headers, _, _)) => assert_eq!(headers.len(), 55),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn keyword_record_should_parse_a_keyword_record(){
        let data = "OBJECT  = 'EPIC 200164267'     / string version of target id                    "
            .as_bytes();

        let result = keyword_record(data);

        match result {
            IResult::Done(_,k) => assert_eq!(k, Keyword::OBJECT),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn keyword_should_parse_a_keyword(){
        let data = "OBJECT  "
            .as_bytes();

        let result = keyword(data);

        match result {
            IResult::Done(_, keyword) => assert_eq!(keyword, Keyword::OBJECT),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn end_record_should_parse_an_END_record(){
        let data = "END                                                                             "
            .as_bytes();

        let result = end_record(data);

        match result {
            IResult::Done(_, keyword) => assert_eq!(keyword, Keyword::END),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn blank_record_should_parse_a_BLANK_record(){
        let data = "                                                                                "
            .as_bytes();

        let result = blank_record(data);

        match result {
            IResult::Done(_, record) => assert_eq!(record, BlankRecord),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }
}
<commit_msg>Still obviously wrong, but now in the structure of keyword parser function<commit_after>//! The parser module is responsible for parsing FITS files.

use std::str;
use std::str::FromStr;
use super::types::{Keyword, BlankRecord};

named!(fits<&[u8], ((Vec<Keyword>, Keyword, Vec<BlankRecord>), Vec<&[u8]>) >,
       pair!(primary_header, many0!( take!(2880) )));

named!(primary_header<&[u8], (Vec<Keyword>, Keyword, Vec<BlankRecord>)>,
       tuple!(
           many0!(keyword_record),
           end_record,
           many0!(blank_record)
       ));

named!(keyword_record<&[u8], Keyword>,
       map_res!(
           map_res!(
               map!(
                   tuple!(
                       take!(8),
                       tag!("="),
                       take!(71)
                   ), |(slice, _, _) : (&[u8], &[u8], &[u8])| {
                       "OBJECT".as_bytes() // TODO obviously wrong, correct it
                   }),
               str::from_utf8),
           Keyword::from_str));

named!(keyword<&[u8], Keyword>,
       map_res!(
           map_res!(
               take!(8),
               str::from_utf8),
           Keyword::from_str
       ));

named!(end_record<&[u8], Keyword>,
       map!(
           pair!(tag!("END"), count!(tag!(" "), 77)),
           |_| { Keyword::END }
       ));

named!(blank_record<&[u8], BlankRecord>,
       map!(
           count!(tag!(" "), 80),
           |_| { BlankRecord }
       ));

#[cfg(test)]
mod tests {
    use nom::{IResult};
    use super::super::types::{Keyword, BlankRecord};
    use super::{fits, primary_header, keyword_record, keyword, end_record, blank_record};

    #[test]
    fn it_should_parse_a_fits_file(){
        let data = include_bytes!("../../assets/images/k2-trappist1-unofficial-tpf-long-cadence.fits");

        let result = fits(data);

        match result {
            IResult::Done(_, (header, blocks)) => {
                assert_eq!(blocks.len(), 3675);
            },
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn primary_header_should_parse_a_primary_header(){
        let data = include_bytes!("../../assets/images/k2-trappist1-unofficial-tpf-long-cadence.fits");

        let result = primary_header(&data[0..(2*2880)]);

        match result {
            IResult::Done(_, (headers, _, _)) => assert_eq!(headers.len(), 55),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn keyword_record_should_parse_a_keyword_record(){
        let data = "OBJECT  = 'EPIC 200164267'     / string version of target id                    "
            .as_bytes();

        let result = keyword_record(data);

        match result {
            IResult::Done(_,k) => assert_eq!(k, Keyword::OBJECT),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn keyword_should_parse_a_keyword(){
        let data = "OBJECT  "
            .as_bytes();

        let result = keyword(data);

        match result {
            IResult::Done(_, keyword) => assert_eq!(keyword, Keyword::OBJECT),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn end_record_should_parse_an_END_record(){
        let data = "END                                                                             "
            .as_bytes();

        let result = end_record(data);

        match result {
            IResult::Done(_, keyword) => assert_eq!(keyword, Keyword::END),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }

    #[test]
    fn blank_record_should_parse_a_BLANK_record(){
        let data = "                                                                                "
            .as_bytes();

        let result = blank_record(data);

        match result {
            IResult::Done(_, record) => assert_eq!(record, BlankRecord),
            IResult::Error(_) => panic!("Did not expect an error"),
            IResult::Incomplete(_) => panic!("Did not expect to be incomplete")
        }
    }
}
<|endoftext|>


<commit_before>static CRCTABLE : [u32, ..256] = [
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
    0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
    0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
    0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
    0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
    0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
    0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
    0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
    0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
    0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
    0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
    0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
    0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
    0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
    0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
    0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
    0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
    0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
];

/// Takes a buffer of bytes (u8 vector) and computes its CRC32 as used
/// in PKZip.
pub fn crc32(buf: &[u8]) -> u32 {
    let mut r = 0xffffffffu32;
    for byte in buf.iter() {
        let idx = byte ^ ((r & 0xff) as u8);
        r = (r >> 8) ^ CRCTABLE[idx as uint];
    }

    return r ^ 0xffffffffu32;
}

<commit_msg>language changes: no autoref on operands.<commit_after>static CRCTABLE : [u32, ..256] = [
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
    0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
    0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
    0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
    0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
    0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
    0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
    0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
    0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
    0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
    0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
    0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
    0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
    0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
    0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
    0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
    0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
    0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
];

/// Takes a buffer of bytes (u8 vector) and computes its CRC32 as used
/// in PKZip.
pub fn crc32(buf: &[u8]) -> u32 {
    let mut r = 0xffffffffu32;
    for &byte in buf.iter() {
        let idx = byte ^ ((r & 0xff) as u8);
        r = (r >> 8) ^ CRCTABLE[idx as uint];
    }

    return r ^ 0xffffffffu32;
}

<|endoftext|>


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

//!
//! Functions for mapping sets of symbol ranges onto other sets of symbol ranges.
//!
//! The most important thing that this does is deal with changing a set of overlapping symbol ranges into a set
//! of non-overlapping ranges. This is needed because the DFA compiler assumes that symbols are unique. The
//! function `Ndfa::fix_overlapping_ranges` in particular makes use of this to generate an NDFA suitable as input
//! to the DFA compiler.
//!
//! # Example
//!
//! ```
//! # use concordance::*;
//! # use ndfa::overlapping_symbols::*;
//! let mut map = SymbolMap::new();
//!
//! map.add_range(&SymbolRange::new(0, 10));
//! map.add_range(&SymbolRange::new(5, 15));
//!
//! let without_overlaps = map.to_non_overlapping_map();
//!
//! let ranges = without_overlaps.find_overlapping_ranges(&SymbolRange::new(0, 10)); // 0-4, 5-10
//! ```
//!

use std::cmp::Ordering;

use super::symbol_range::*;
use super::countable::*;

///
/// A symbol map maps from one set of symbol ranges to another
///
pub struct SymbolMap<Symbol: Ord+Clone+Countable> {
    // Ranges in this symbol map
    ranges: Vec<SymbolRange<Symbol>>,
}

impl<Symbol: Ord+Clone+Countable> SymbolMap<Symbol> {
    ///
    /// Creates a new symbol map
    ///
    pub fn new() -> SymbolMap<Symbol> {
        SymbolMap { ranges: vec![] }
    }

    ///
    /// Orders two symbols (makes unordered symbols equal)
    ///
    #[inline]
    fn order_symbols(a: &Symbol, b: &Symbol) -> Ordering {
        a.cmp(b)
    }

    ///
    /// Orders two symbol ranges
    ///
    #[inline]
    fn order_ranges(a: &SymbolRange<Symbol>, b: &SymbolRange<Symbol>) -> Ordering {
        let ordering = SymbolMap::order_symbols(&a.lowest, &b.lowest);

        if ordering == Ordering::Equal {
            SymbolMap::order_symbols(&a.highest, &b.highest)
        } else {
            ordering
        }
    }

    ///
    /// Adds a range to those that are known about by this object
    ///
    pub fn add_range(&mut self, range: &SymbolRange<Symbol>) {
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Insert the range if it is not already in the map
        if let Err(insertion_pos) = existing {
            self.ranges.insert(insertion_pos, range.clone());
        }
    }

    ///
    /// Finds the ranges in this map that overlap the target ranges
    ///
    pub fn find_overlapping_ranges(&self, range: &SymbolRange<Symbol>) -> Vec<&SymbolRange<Symbol>> {
        let mut result = vec![];

        // Find the first range that matches (or the insertion position, which should be the first range wit a lowest value higher than the target range)
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Start returning values from here
        let mut pos = match existing {
            Ok(found_position) => found_position,
            Err(insert_position) => insert_position
        };

        // Move backwards if the previous position overlaps this one
        if pos > 0 && self.ranges[pos-1].highest >= range.lowest {
            pos -= 1;
        }

        // TODO: can we construct a set of ranges such that one is missed here? Think maybe we can
        while pos < self.ranges.len() && self.ranges[pos].lowest <= range.highest {
            result.push(&self.ranges[pos]);
            pos += 1;
        }

        result
    }

    ///
    /// Creates a non-overlapping range from an overlapping one
    ///
    pub fn to_non_overlapping_map(&self) -> SymbolMap<Symbol> {
        // Stack, popping the lowest ordered ranges first
        let mut to_process = self.ranges.clone();
        to_process.reverse();

        let mut result = vec![];

        while let Some(might_overlap) = to_process.pop() {
            if let Some(overlap_with) = to_process.pop() {
                // Stack has two ranges on top. They might overlap
                if !might_overlap.overlaps(&overlap_with) {
                    // Doesn't overlap: can just push might_overlap and continue
                    result.push(might_overlap);
                    to_process.push(overlap_with);
                } else {
                    // Got an overlap
                    if might_overlap == overlap_with {
                        // Ranges are the same, just discard one
                        to_process.push(overlap_with);
                    } else if might_overlap.lowest == overlap_with.lowest {
                        // Ranges start at the same location. We need to divide them in case more than two ranges are overlapping
                        let (smaller_range, larger_range) = (might_overlap, overlap_with);      // Because of the sort order

                        // Chop out the smaller range from the larger range, then insert into the stack in order
                        let larger_range_without_smaller_range = SymbolRange::new(smaller_range.highest.next(), larger_range.highest.clone());

                        if let Err(insertion_pos) = to_process.binary_search_by(|test_range| { SymbolMap::order_ranges(&larger_range_without_smaller_range, test_range) }) {
                            to_process.insert(insertion_pos, larger_range_without_smaller_range);
                        }

                        to_process.push(smaller_range);
                    } else {
                        // There's a range from the lowest of the first range to the lowest of the second ranges
                        result.push(SymbolRange::new(might_overlap.lowest.clone(), overlap_with.lowest.prev()));

                        // Chop out the bit we just pushed from might_overlap and push back both ranges
                        // Maintain sort order depending on highest (as lowest for both ranges will be equal)
                        if overlap_with.highest > might_overlap.highest {
                            to_process.push(overlap_with.clone());
                            to_process.push(SymbolRange::new(overlap_with.lowest, might_overlap.highest));
                        } else {
                            to_process.push(SymbolRange::new(overlap_with.lowest.clone(), might_overlap.highest));
                            to_process.push(overlap_with);
                        }
                    }
                }
            } else {
                // Last range should never overlap
                result.push(might_overlap);
            }
        }

        // Ranges should already be sorted as we worked from left to right
        SymbolMap { ranges: result }
    }
}

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

    #[test]
    fn can_lookup_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let bottom = map.find_overlapping_ranges(&SymbolRange::new(0, 1));
        let all    = map.find_overlapping_ranges(&SymbolRange::new(1, 3));
        let top    = map.find_overlapping_ranges(&SymbolRange::new(6, 6));

        assert!(bottom == vec![&SymbolRange::new(0, 4)]);
        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(2, 5), &SymbolRange::new(3, 6)]);
        assert!(top == vec![&SymbolRange::new(3, 6)]);
    }

    #[test]
    fn can_lookup_mid_range() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(5, 10));
        map.add_range(&SymbolRange::new(11, 15));

        let mid = map.find_overlapping_ranges(&SymbolRange::new(1, 3));

        assert!(mid == vec![&SymbolRange::new(0, 4)]);
    }

    #[test]
    fn works_with_duplicate_lower_values() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 2));
        map.add_range(&SymbolRange::new(0, 3));

        let all    = map.find_overlapping_ranges(&SymbolRange::new(0, 1));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(0, 3)]);
    }

    #[test]
    fn can_get_non_overlapping_map() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 2), &SymbolRange::new(3, 4), &SymbolRange::new(5, 5), &SymbolRange::new(6, 6)]);
    }

    #[test]
    fn can_get_non_overlapping_map_with_single_symbols() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(2, 2));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 2), &SymbolRange::new(3, 5), &SymbolRange::new(6, 6)]);
    }

    #[test]
    fn can_deal_with_duplicate_symbols() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(2, 2));
        map.add_range(&SymbolRange::new(3, 6));

        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(2, 2));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 2), &SymbolRange::new(3, 5), &SymbolRange::new(6, 6)]);
    }

    #[test]
    fn generate_correctly_for_single_symbol() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 0)]);
    }

    #[test]
    fn generate_correctly_for_two_single_symbols() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));
        map.add_range(&SymbolRange::new(1, 1));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 0), &SymbolRange::new(1, 1)]);
    }

    #[test]
    fn generate_correctly_for_non_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 1));
        map.add_range(&SymbolRange::new(2, 4));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 4)]);
    }

    #[test]
    fn generate_correctly_for_single_overlap() {
        let mut map = SymbolMap::new();

        // Here the symbol '5' is in both ranges, so we should generate it as a seperate range in the non-overlapping version
        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(5, 10));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(5,5), &SymbolRange::new(6, 10)]);
    }

    #[test]
    fn can_get_non_overlapping_map_with_single_symbols_at_start() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));
        map.add_range(&SymbolRange::new(0, 1));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 0), &SymbolRange::new(1, 1)]);
    }

    #[test]
    fn can_get_non_overlapping_map_with_single_symbols_at_start_and_gap() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));
        map.add_range(&SymbolRange::new(0, 1));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 0), &SymbolRange::new(1, 1), &SymbolRange::new(3, 6)]);
    }
}
<commit_msg>Fix test error<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! Functions for mapping sets of symbol ranges onto other sets of symbol ranges.
//!
//! The most important thing that this does is deal with changing a set of overlapping symbol ranges into a set
//! of non-overlapping ranges. This is needed because the DFA compiler assumes that symbols are unique. The
//! function `Ndfa::fix_overlapping_ranges` in particular makes use of this to generate an NDFA suitable as input
//! to the DFA compiler.
//!
//! # Example
//!
//! ```
//! # use concordance::*;
//! # use concordance::overlapping_symbols::*;
//! let mut map = SymbolMap::new();
//!
//! map.add_range(&SymbolRange::new(0, 10));
//! map.add_range(&SymbolRange::new(5, 15));
//!
//! let without_overlaps = map.to_non_overlapping_map();
//!
//! let ranges = without_overlaps.find_overlapping_ranges(&SymbolRange::new(0, 10)); // 0-4, 5-10
//! ```
//!

use std::cmp::Ordering;

use super::symbol_range::*;
use super::countable::*;

///
/// A symbol map maps from one set of symbol ranges to another
///
pub struct SymbolMap<Symbol: Ord+Clone+Countable> {
    // Ranges in this symbol map
    ranges: Vec<SymbolRange<Symbol>>,
}

impl<Symbol: Ord+Clone+Countable> SymbolMap<Symbol> {
    ///
    /// Creates a new symbol map
    ///
    pub fn new() -> SymbolMap<Symbol> {
        SymbolMap { ranges: vec![] }
    }

    ///
    /// Orders two symbols (makes unordered symbols equal)
    ///
    #[inline]
    fn order_symbols(a: &Symbol, b: &Symbol) -> Ordering {
        a.cmp(b)
    }

    ///
    /// Orders two symbol ranges
    ///
    #[inline]
    fn order_ranges(a: &SymbolRange<Symbol>, b: &SymbolRange<Symbol>) -> Ordering {
        let ordering = SymbolMap::order_symbols(&a.lowest, &b.lowest);

        if ordering == Ordering::Equal {
            SymbolMap::order_symbols(&a.highest, &b.highest)
        } else {
            ordering
        }
    }

    ///
    /// Adds a range to those that are known about by this object
    ///
    pub fn add_range(&mut self, range: &SymbolRange<Symbol>) {
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Insert the range if it is not already in the map
        if let Err(insertion_pos) = existing {
            self.ranges.insert(insertion_pos, range.clone());
        }
    }

    ///
    /// Finds the ranges in this map that overlap the target ranges
    ///
    pub fn find_overlapping_ranges(&self, range: &SymbolRange<Symbol>) -> Vec<&SymbolRange<Symbol>> {
        let mut result = vec![];

        // Find the first range that matches (or the insertion position, which should be the first range wit a lowest value higher than the target range)
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Start returning values from here
        let mut pos = match existing {
            Ok(found_position) => found_position,
            Err(insert_position) => insert_position
        };

        // Move backwards if the previous position overlaps this one
        if pos > 0 && self.ranges[pos-1].highest >= range.lowest {
            pos -= 1;
        }

        // TODO: can we construct a set of ranges such that one is missed here? Think maybe we can
        while pos < self.ranges.len() && self.ranges[pos].lowest <= range.highest {
            result.push(&self.ranges[pos]);
            pos += 1;
        }

        result
    }

    ///
    /// Creates a non-overlapping range from an overlapping one
    ///
    pub fn to_non_overlapping_map(&self) -> SymbolMap<Symbol> {
        // Stack, popping the lowest ordered ranges first
        let mut to_process = self.ranges.clone();
        to_process.reverse();

        let mut result = vec![];

        while let Some(might_overlap) = to_process.pop() {
            if let Some(overlap_with) = to_process.pop() {
                // Stack has two ranges on top. They might overlap
                if !might_overlap.overlaps(&overlap_with) {
                    // Doesn't overlap: can just push might_overlap and continue
                    result.push(might_overlap);
                    to_process.push(overlap_with);
                } else {
                    // Got an overlap
                    if might_overlap == overlap_with {
                        // Ranges are the same, just discard one
                        to_process.push(overlap_with);
                    } else if might_overlap.lowest == overlap_with.lowest {
                        // Ranges start at the same location. We need to divide them in case more than two ranges are overlapping
                        let (smaller_range, larger_range) = (might_overlap, overlap_with);      // Because of the sort order

                        // Chop out the smaller range from the larger range, then insert into the stack in order
                        let larger_range_without_smaller_range = SymbolRange::new(smaller_range.highest.next(), larger_range.highest.clone());

                        if let Err(insertion_pos) = to_process.binary_search_by(|test_range| { SymbolMap::order_ranges(&larger_range_without_smaller_range, test_range) }) {
                            to_process.insert(insertion_pos, larger_range_without_smaller_range);
                        }

                        to_process.push(smaller_range);
                    } else {
                        // There's a range from the lowest of the first range to the lowest of the second ranges
                        result.push(SymbolRange::new(might_overlap.lowest.clone(), overlap_with.lowest.prev()));

                        // Chop out the bit we just pushed from might_overlap and push back both ranges
                        // Maintain sort order depending on highest (as lowest for both ranges will be equal)
                        if overlap_with.highest > might_overlap.highest {
                            to_process.push(overlap_with.clone());
                            to_process.push(SymbolRange::new(overlap_with.lowest, might_overlap.highest));
                        } else {
                            to_process.push(SymbolRange::new(overlap_with.lowest.clone(), might_overlap.highest));
                            to_process.push(overlap_with);
                        }
                    }
                }
            } else {
                // Last range should never overlap
                result.push(might_overlap);
            }
        }

        // Ranges should already be sorted as we worked from left to right
        SymbolMap { ranges: result }
    }
}

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

    #[test]
    fn can_lookup_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let bottom = map.find_overlapping_ranges(&SymbolRange::new(0, 1));
        let all    = map.find_overlapping_ranges(&SymbolRange::new(1, 3));
        let top    = map.find_overlapping_ranges(&SymbolRange::new(6, 6));

        assert!(bottom == vec![&SymbolRange::new(0, 4)]);
        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(2, 5), &SymbolRange::new(3, 6)]);
        assert!(top == vec![&SymbolRange::new(3, 6)]);
    }

    #[test]
    fn can_lookup_mid_range() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(5, 10));
        map.add_range(&SymbolRange::new(11, 15));

        let mid = map.find_overlapping_ranges(&SymbolRange::new(1, 3));

        assert!(mid == vec![&SymbolRange::new(0, 4)]);
    }

    #[test]
    fn works_with_duplicate_lower_values() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 2));
        map.add_range(&SymbolRange::new(0, 3));

        let all    = map.find_overlapping_ranges(&SymbolRange::new(0, 1));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(0, 3)]);
    }

    #[test]
    fn can_get_non_overlapping_map() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 2), &SymbolRange::new(3, 4), &SymbolRange::new(5, 5), &SymbolRange::new(6, 6)]);
    }

    #[test]
    fn can_get_non_overlapping_map_with_single_symbols() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(2, 2));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 2), &SymbolRange::new(3, 5), &SymbolRange::new(6, 6)]);
    }

    #[test]
    fn can_deal_with_duplicate_symbols() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(2, 2));
        map.add_range(&SymbolRange::new(3, 6));

        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(2, 2));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 2), &SymbolRange::new(3, 5), &SymbolRange::new(6, 6)]);
    }

    #[test]
    fn generate_correctly_for_single_symbol() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 0)]);
    }

    #[test]
    fn generate_correctly_for_two_single_symbols() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));
        map.add_range(&SymbolRange::new(1, 1));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 0), &SymbolRange::new(1, 1)]);
    }

    #[test]
    fn generate_correctly_for_non_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 1));
        map.add_range(&SymbolRange::new(2, 4));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 1), &SymbolRange::new(2, 4)]);
    }

    #[test]
    fn generate_correctly_for_single_overlap() {
        let mut map = SymbolMap::new();

        // Here the symbol '5' is in both ranges, so we should generate it as a seperate range in the non-overlapping version
        map.add_range(&SymbolRange::new(0, 5));
        map.add_range(&SymbolRange::new(5, 10));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 10));

        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(5,5), &SymbolRange::new(6, 10)]);
    }

    #[test]
    fn can_get_non_overlapping_map_with_single_symbols_at_start() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));
        map.add_range(&SymbolRange::new(0, 1));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 0), &SymbolRange::new(1, 1)]);
    }

    #[test]
    fn can_get_non_overlapping_map_with_single_symbols_at_start_and_gap() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 0));
        map.add_range(&SymbolRange::new(0, 1));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 0), &SymbolRange::new(1, 1), &SymbolRange::new(3, 6)]);
    }
}
<|endoftext|>


<commit_before>
#![allow(dead_code)]

use std::cmp;
use raft::storage::Storage;
use proto::raftpb::{HardState, ConfState, Entry, Snapshot, Message};
use raft::progress::{Progress, Inflights};
use raft::errors::{Result, Error, other};
use std::collections::HashMap;
use raft::raft_log::RaftLog;

#[derive(Debug, PartialEq)]
enum StateRole {
    Follower,
    Candidate,
    Leader,
    Invalid,
}

impl Default for StateRole {
    fn default() -> StateRole {
        StateRole::Invalid
    }
}

const INVALID_ID: u64 = 0;

// Config contains the parameters to start a raft.
#[derive( Default)]
pub struct Config {
    // id is the identity of the local raft. ID cannot be 0.
    id: u64,

    // peers contains the IDs of all nodes (including self) in
    // the raft cluster. It should only be set when starting a new
    // raft cluster.
    // Restarting raft from previous configuration will panic if
    // peers is set.
    // peer is private and only used for testing right now.
    peers: Vec<u64>,

    // ElectionTick is the election timeout. If a follower does not
    // receive any message from the leader of current term during
    // ElectionTick, it will become candidate and start an election.
    // ElectionTick must be greater than HeartbeatTick. We suggest
    // to use ElectionTick = 10 * HeartbeatTick to avoid unnecessary
    // leader switching.
    election_tick: usize,
    // HeartbeatTick is the heartbeat usizeerval. A leader sends heartbeat
    // message to mausizeain the leadership every heartbeat usizeerval.
    heartbeat_tick: usize,

    // Storage is the storage for raft. raft generates entires and
    // states to be stored in storage. raft reads the persisted entires
    // and states out of Storage when it needs. raft reads out the previous
    // state and configuration out of storage when restarting.
    storage: Option<Box<Storage>>,
    // Applied is the last applied index. It should only be set when restarting
    // raft. raft will not return entries to the application smaller or equal to Applied.
    // If Applied is unset when restarting, raft might return previous applied entries.
    // This is a very application dependent configuration.
    applied: u64,

    // MaxSizePerMsg limits the max size of each append message. Smaller value lowers
    // the raft recovery cost(initial probing and message lost during normal operation).
    // On the other side, it might affect the throughput during normal replication.
    // Note: math.MaxUusize64 for unlimited, 0 for at most one entry per message.
    max_size_per_msg: u64,
    // max_inflights_msgs limits the max number of in-flight append messages during optimistic
    // replication phase. The application transportation layer usually has its own sending
    // buffer over TCP/UDP. Setting MaxInflightMsgs to avoid overflowing that sending buffer.
    // TODO (xiangli): feedback to application to limit the proposal rate?
    max_inflights_msgs: usize,

    // check_quorum specifies if the leader should check quorum activity. Leader steps down when
    // quorum is not active for an electionTimeout.
    check_quorum: bool,
}

impl Config {
    pub fn validate(&self) -> Result<()> {
        if self.id == INVALID_ID {
            return Err(other("invalid node id"));
        }

        if self.heartbeat_tick <= 0 {
            return Err(other("heartbeat tick must greater than 0"));
        }

        if self.election_tick <= self.heartbeat_tick {
            return Err(other("election tick must be greater than heartbeat tick"));
        }

        if self.max_inflights_msgs <= 0 {
            return Err(other("max inflight messages must be greater than 0"));
        }

        Ok(())
    }
}

#[derive(Default)]
struct Raft {
    hs: HardState,

    id: u64,

    max_inflight: usize,
    max_msg_size: u64,
    prs: HashMap<u64, Progress>,

    state: StateRole,

    votes: HashMap<u64, bool>,

    msgs: Vec<Message>,

    // the leader id
    lead: u64,

    // New configuration is ignored if there exists unapplied configuration.
    pending_conf: bool,

    // number of ticks since it reached last electionTimeout when it is leader
    // or candidate.
    // number of ticks since it reached last electionTimeout or received a
    // valid message from current leader when it is a follower.
    election_elapsed: usize,

    // number of ticks since it reached last heartbeatTimeout.
    // only leader keeps heartbeatElapsed.
    heartbeat_elapsed: usize,

    check_quorum: bool,

    heartbeat_timeout: usize,
    election_timeout: usize,
    tick: Vec<Box<FnMut()>>,
    step: Vec<Box<FnMut(&Message)>>,
}

impl Raft {
    fn newRaft<T>(c: &Config) -> Raft
        where T: Storage
    {
        c.validate().map_err(|e| panic!(e));
        let mut raftlog = RaftLog::new(c.storage);
        let state = &c.storage.initial_state();
        state.map_err(|e| panic!(e));
        let hs = &state.unwrap().hard_state;
        let cs = &state.unwrap().conf_state;
        let mut peers = c.peers.into_iter().collect::<Vec<u64>>();
        if cs.get_nodes().len() > 0 {
            if peers.len() > 0 {
                panic!("cannot specify both newRaft(peers) and conf_state.nodes")
            }
            peers = cs.get_nodes().into_iter().map(|&x| x).collect::<Vec<u64>>();
        }

        let mut tmp: HashMap<u64, Progress> = HashMap::new();
        for id in peers {
            tmp.insert(id,
                       Progress {
                           next_idx: 1,
                           ins: Inflights::new(c.max_inflights_msgs),
                           ..Default::default()
                       });
        }
        // empty state
        if hs == &HardState::new() {

        }
        Raft {
            id: c.id,
            lead: INVALID_ID,
            max_msg_size: c.max_size_per_msg,
            max_inflight: c.max_inflights_msgs,
            election_timeout: c.election_tick,
            heartbeat_timeout: c.heartbeat_tick,
            check_quorum: c.check_quorum,
            prs: tmp,
            tick: Vec::new(),
            step: Vec::new(),
            ..Default::default()
        }
    }

    pub fn do_nothing(&self) {}
}
<commit_msg>port raft<commit_after>
#![allow(dead_code)]
use std::cmp;
use raft::storage::{Storage, ThreadSafeStorage};
use proto::raftpb::{HardState, ConfState, Entry, Snapshot, Message, MessageType};
use protobuf::repeated::RepeatedField;
use raft::progress::{Progress, Inflights, ProgressState};
use raft::errors::{Result, Error, other, StorageError};
use std::collections::HashMap;
use raft::raft_log::RaftLog;
use std::sync::Arc;
use std::fmt;

#[derive(Debug, PartialEq, Clone, Copy)]
enum StateRole {
    Follower,
    Candidate,
    Leader,
    Invalid,
}

impl Default for StateRole {
    fn default() -> StateRole {
        StateRole::Invalid
    }
}

const INVALID_ID: u64 = 0;

/// Config contains the parameters to start a raft.
#[derive(Default)]
pub struct Config<T: Storage + Sync> {
    /// id is the identity of the local raft. ID cannot be 0.
    id: u64,

    /// peers contains the IDs of all nodes (including self) in
    /// the raft cluster. It should only be set when starting a new
    /// raft cluster.
    /// Restarting raft from previous configuration will panic if
    /// peers is set.
    /// peer is private and only used for testing right now.
    peers: Vec<u64>,

    /// ElectionTick is the election timeout. If a follower does not
    /// receive any message from the leader of current term during
    /// ElectionTick, it will become candidate and start an election.
    /// ElectionTick must be greater than HeartbeatTick. We suggest
    /// to use ElectionTick = 10 * HeartbeatTick to avoid unnecessary
    /// leader switching.
    election_tick: usize,
    /// HeartbeatTick is the heartbeat usizeerval. A leader sends heartbeat
    /// message to mausizeain the leadership every heartbeat usizeerval.
    heartbeat_tick: usize,

    /// Storage is the storage for raft. raft generates entires and
    /// states to be stored in storage. raft reads the persisted entires
    /// and states out of Storage when it needs. raft reads out the previous
    /// state and configuration out of storage when restarting.
    storage: Option<Arc<ThreadSafeStorage<T>>>,
    /// Applied is the last applied index. It should only be set when restarting
    /// raft. raft will not return entries to the application smaller or equal to Applied.
    /// If Applied is unset when restarting, raft might return previous applied entries.
    /// This is a very application dependent configuration.
    applied: u64,

    /// MaxSizePerMsg limits the max size of each append message. Smaller value lowers
    /// the raft recovery cost(initial probing and message lost during normal operation).
    /// On the other side, it might affect the throughput during normal replication.
    /// Note: math.MaxUusize64 for unlimited, 0 for at most one entry per message.
    max_size_per_msg: u64,
    /// max_inflight_msgs limits the max number of in-flight append messages during optimistic
    /// replication phase. The application transportation layer usually has its own sending
    /// buffer over TCP/UDP. Setting MaxInflightMsgs to avoid overflowing that sending buffer.
    /// TODO (xiangli): feedback to application to limit the proposal rate?
    max_inflight_msgs: usize,

    /// check_quorum specifies if the leader should check quorum activity. Leader steps down when
    /// quorum is not active for an electionTimeout.
    check_quorum: bool,
}

impl<T: Storage + Sync> Config<T> {
    pub fn validate(&self) -> Result<()> {
        if self.id == INVALID_ID {
            return Err(other("invalid node id"));
        }

        if self.heartbeat_tick <= 0 {
            return Err(other("heartbeat tick must greater than 0"));
        }

        if self.election_tick <= self.heartbeat_tick {
            return Err(other("election tick must be greater than heartbeat tick"));
        }

        if self.storage.is_none() {
            return Err(other("storage should be specified"));
        }

        if self.max_inflight_msgs <= 0 {
            return Err(other("max inflight messages must be greater than 0"));
        }

        Ok(())
    }
}

// SoftState provides state that is useful for logging and debugging.
// The state is volatile and does not need to be persisted to the WAL.
#[derive(Default, PartialEq)]
struct SoftState {
    lead: u64,
    raft_state: StateRole,
}

struct Raft<T: Storage + Sync> {
    hs: HardState,

    id: u64,

    /// the log
    raft_log: RaftLog<T>,

    max_inflight: usize,
    max_msg_size: u64,
    prs: HashMap<u64, Progress>,

    state: StateRole,

    votes: HashMap<u64, bool>,

    msgs: Vec<Message>,

    /// the leader id
    lead: u64,

    /// New configuration is ignored if there exists unapplied configuration.
    pending_conf: bool,

    /// number of ticks since it reached last electionTimeout when it is leader
    /// or candidate.
    /// number of ticks since it reached last electionTimeout or received a
    /// valid message from current leader when it is a follower.
    election_elapsed: usize,

    /// number of ticks since it reached last heartbeatTimeout.
    /// only leader keeps heartbeatElapsed.
    heartbeat_elapsed: usize,

    check_quorum: bool,

    heartbeat_timeout: usize,
    election_timeout: usize,
}

impl<T: Storage + Sync> Raft<T> {
    fn new(c: &Config<T>) -> Raft<T> {
        c.validate().expect("configuration is invalid");
        let store = c.storage.as_ref().unwrap().clone();
        let rs = (**store).initial_state().expect("");
        let mut raft_log = RaftLog::new(store);
        let mut peers = &*c.peers;
        if rs.conf_state.get_nodes().len() > 0 {
            if peers.len() > 0 {
                // TODO(bdarnell): the peers argument is always nil except in
                // tests; the argument should be removed and these tests should be
                // updated to specify their nodes through a snap
                panic!("cannot specify both new(peers) and ConfState.Nodes")
            }
            peers = rs.conf_state.get_nodes();
        }
        let mut r = Raft {
            hs: HardState::new(),
            id: c.id,
            raft_log: raft_log,
            max_inflight: c.max_inflight_msgs,
            max_msg_size: c.max_size_per_msg,
            prs: HashMap::with_capacity(peers.len()),
            state: StateRole::Invalid,
            votes: HashMap::new(),
            msgs: vec![],
            lead: INVALID_ID,
            pending_conf: false,
            election_elapsed: 0,
            heartbeat_elapsed: 0,
            check_quorum: c.check_quorum,
            heartbeat_timeout: c.heartbeat_tick,
            election_timeout: c.election_tick,
        };
        for p in peers {
            r.prs.insert(*p,
                         Progress {
                             next_idx: 1,
                             ins: Inflights::new(r.max_inflight),
                             ..Default::default()
                         });
        }
        if rs.hard_state != HardState::new() {
            r.load_state(rs.hard_state);
        }
        if c.applied > 0 {
            r.raft_log.applied_to(c.applied);
        }
        r.become_follower(r.hs.get_term(), INVALID_ID);

        let mut nodes_str = String::new();
        for n in r.nodes() {
            nodes_str = nodes_str + &format!("{:?}", n);
            nodes_str = nodes_str + ",";
        }
        let nodes_str_len = nodes_str.len();
        nodes_str.remove(nodes_str_len - 1);
        info!("newRaft {:x} [peers: [{}], term: {:?}, commit: {}, applied: {}, last_index: {}, \
               last_term: {}]",
              r.id,
              nodes_str,
              r.hs.get_term(),
              r.raft_log.get_committed(),
              r.raft_log.get_applied(),
              r.raft_log.last_index(),
              r.raft_log.last_term());
        r
    }

    fn has_leader(&self) -> bool {
        self.lead != INVALID_ID
    }

    fn soft_state(&self) -> SoftState {
        SoftState {
            lead: self.lead,
            raft_state: self.state,
        }
    }

    fn quorum(&self) -> usize {
        self.prs.len() / 2 + 1
    }

    fn nodes(&self) -> Vec<u64> {
        let mut nodes = Vec::with_capacity(self.prs.len());
        nodes.extend(self.prs.keys());
        nodes.sort();
        nodes
    }

    // send persists state to stable storage and then sends to its mailbox.
    fn send(&mut self, m: Message) {
        let mut m = m;
        m.set_from(self.id);
        // do not attach term to MsgPropose
        // proposals are a way to forward to the leader and
        // should be treated as local message.
        if m.get_field_type() != MessageType::MsgPropose {
            m.set_term(self.hs.get_term());
        }
        self.msgs.push(m);
    }

    fn prepare_send_snapshot(&mut self, m: &mut Message, to: u64) {
        let pr = self.prs.get_mut(&to).unwrap();
        if !pr.recent_active {
            debug!("ignore sending snapshot to {:x} since it is not recently active",
                   to);
            return;
        }

        m.set_field_type(MessageType::MsgSnapshot);
        let snapshot_r = self.raft_log.snapshot();
        if let Err(e) = snapshot_r {
            if e == Error::Store(StorageError::SnapshotTemporarilyUnavailable) {
                debug!("{:x} failed to send snapshot to {:x} because snapshot is termporarily \
                        unavailable",
                       self.id,
                       to);
                return;
            }
            panic!(e);
        }
        let snapshot = snapshot_r.unwrap();
        if snapshot.get_metadata().get_index() == 0 {
            panic!("need non-empty snapshot");
        }
        let (sindex, sterm) = (snapshot.get_metadata().get_index(),
                               snapshot.get_metadata().get_term());
        m.set_snapshot(snapshot.clone());
        debug!("{:x} [firstindex: {}, commit: {}] sent snapshot[index: {}, term: {}] to {:x} \
                [{:?}]",
               self.id,
               self.raft_log.first_index(),
               self.hs.get_commit(),
               sindex,
               sterm,
               to,
               pr);
        pr.become_snapshot(sindex);
        debug!("{:x} paused sending replication messages to {:x} [{:?}]",
               self.id,
               to,
               pr);
    }

    fn prepare_send_entries(&mut self, m: &mut Message, to: u64, term: u64, ents: Vec<Entry>) {
        let pr = self.prs.get_mut(&to).unwrap();
        m.set_field_type(MessageType::MsgAppend);
        m.set_index(pr.next_idx - 1);
        m.set_logTerm(term);
        m.set_entries(RepeatedField::from_vec(ents));
        m.set_commit(self.raft_log.get_committed());
        if m.get_entries().len() != 0 {
            match pr.state {
                ProgressState::Replicate => {
                    let last = m.get_entries().last().unwrap().get_Index();
                    pr.optimistic_update(last);
                    pr.ins.add(last);
                }
                ProgressState::Probe => pr.pause(),
                _ => {
                    panic!("{:x} is sending append in unhandled state {:?}",
                           self.id,
                           pr.state)
                }
            }
        }
    }

    // send_append sends RPC, with entries to the given peer.
    fn send_append(&mut self, to: u64) {
        let (term, ents) = {
            let pr = self.prs.get(&to).unwrap();
            if pr.is_paused() {
                return;
            }
            (self.raft_log.term(pr.next_idx - 1),
             self.raft_log.entries(pr.next_idx, self.max_msg_size))
        };
        let mut m = Message::new();
        m.set_to(to);
        if term.is_err() || ents.is_err() {
            // send snapshot if we failed to get term or entries
            self.prepare_send_snapshot(&mut m, to);
        } else {
            self.prepare_send_entries(&mut m, to, term.unwrap(), ents.unwrap());
        }
        self.send(m);
    }

    // sendHeartbeat sends an empty MsgApp
    fn send_heartbeat(&mut self, to: u64) {
        // Attach the commit as min(to.matched, r.committed).
        // When the leader sends out heartbeat message,
        // the receiver(follower) might not be matched with the leader
        // or it might not have all the committed entries.
        // The leader MUST NOT forward the follower's commit to
        // an unmatched index.
        let commit = cmp::min(self.prs.get(&to).unwrap().matched,
                              self.raft_log.get_committed());
        let mut m = Message::new();
        m.set_to(to);
        m.set_field_type(MessageType::MsgHeartbeat);
        m.set_commit(commit);
        self.send(m);
    }

    // bcastAppend sends RPC, with entries to all peers that are not up-to-date
    // according to the progress recorded in r.prs.
    fn bcast_append(&mut self) {
        let keys: Vec<u64> = self.prs.keys().map(|x| *x).collect();
        for id in keys {
            if id == self.id {
                continue;
            }
            self.send_append(id);
        }
    }

    fn become_follower(&self, term: u64, lead: u64) {}

    fn load_state(&self, hs: HardState) {}
}
<|endoftext|>