<commit_before>extern crate sum_of_multiples;

use sum_of_multiples::*;

#[test]
fn multiples_one() {
    assert_eq!(0, sum_of_multiples(1, &vec![3, 5]))
}

#[test]
#[ignore]
fn multiples_two() {
    assert_eq!(3, sum_of_multiples(4, &vec![3, 5]))
}

#[test]
#[ignore]
fn multiples_three() {
    assert_eq!(23, sum_of_multiples(10, &vec![3, 5]))
}

#[test]
#[ignore]
fn multiples_four() {
    assert_eq!(2318, sum_of_multiples(100, &vec![3, 5]))
}

#[test]
#[ignore]
fn multiples_five() {
    assert_eq!(233168, sum_of_multiples(1000, &vec![3, 5]))
}

#[test]
#[ignore]
fn multiples_six() {
    assert_eq!(51, sum_of_multiples(20, &vec![7, 13, 17]))
}

#[test]
#[ignore]
fn multiples_seven() {
    assert_eq!(30, sum_of_multiples(15, &vec![4, 6]))
}

#[test]
#[ignore]
fn multiples_eight() {
    assert_eq!(4419, sum_of_multiples(150, &vec![5, 6, 8]))
}

#[test]
#[ignore]
fn multiples_nine() {
    assert_eq!(275, sum_of_multiples(51, &vec![5, 25]))
}

#[test]
#[ignore]
fn multiples_ten() {
    assert_eq!(2203160, sum_of_multiples(10000, &vec![43, 47]))
}

#[test]
#[ignore]
fn multiples_eleven() {
    assert_eq!(4950, sum_of_multiples(100, &vec![1]))
}

#[test]
#[ignore]
fn multiples_twelve() {
    assert_eq!(0, sum_of_multiples(10000, &vec![]))
}
<commit_msg>sum-of-multiples: Use `&[...]` instead of `&vec![...]`<commit_after>extern crate sum_of_multiples;

use sum_of_multiples::*;

#[test]
fn multiples_one() {
    assert_eq!(0, sum_of_multiples(1, &[3, 5]))
}

#[test]
#[ignore]
fn multiples_two() {
    assert_eq!(3, sum_of_multiples(4, &[3, 5]))
}

#[test]
#[ignore]
fn multiples_three() {
    assert_eq!(23, sum_of_multiples(10, &[3, 5]))
}

#[test]
#[ignore]
fn multiples_four() {
    assert_eq!(2318, sum_of_multiples(100, &[3, 5]))
}

#[test]
#[ignore]
fn multiples_five() {
    assert_eq!(233168, sum_of_multiples(1000, &[3, 5]))
}

#[test]
#[ignore]
fn multiples_six() {
    assert_eq!(51, sum_of_multiples(20, &[7, 13, 17]))
}

#[test]
#[ignore]
fn multiples_seven() {
    assert_eq!(30, sum_of_multiples(15, &[4, 6]))
}

#[test]
#[ignore]
fn multiples_eight() {
    assert_eq!(4419, sum_of_multiples(150, &[5, 6, 8]))
}

#[test]
#[ignore]
fn multiples_nine() {
    assert_eq!(275, sum_of_multiples(51, &[5, 25]))
}

#[test]
#[ignore]
fn multiples_ten() {
    assert_eq!(2203160, sum_of_multiples(10000, &[43, 47]))
}

#[test]
#[ignore]
fn multiples_eleven() {
    assert_eq!(4950, sum_of_multiples(100, &[1]))
}

#[test]
#[ignore]
fn multiples_twelve() {
    assert_eq!(0, sum_of_multiples(10000, &[]))
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

use crate::web::config::Config;
use crate::web::data::{GeneDetails, OntAnnotationId};

fn make_title(config: &Config, gene_details: &GeneDetails) -> String {
    let name_and_uniquename =
        if let Some(ref name) = gene_details.name {
            format!("{} ({})", name, gene_details.uniquename)
        } else {
            format!("{}", gene_details.uniquename)
        };

    let feature_type =
        if gene_details.feature_type.ends_with(" gene") {
            String::from(gene_details.feature_type.as_str())
        } else {
            format!("{} gene", gene_details.feature_type)
        };

    if let Some(ref product) = gene_details.product {
        format!("{} - {} {} - {}", config.database_name, feature_type,
                name_and_uniquename, product)
    } else {
        format!("{} - {} {}", config.database_name, feature_type, name_and_uniquename)
    }
}

fn gene_header(config: &Config, title: &str) -> String  {
    format!(r##"
  <meta charset="utf-8">
  <title>{}</title>
  <base href="/">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="title" content="{}">
  <meta name="author" content="{}">
  <meta name="description" content="{}">
  <meta name="google-site-verification" content="H8vhCdG7XsSbh-8f20VSipvu2PnZ22YSGZm81jE0-Pk" />
  <link rel="shortcut icon" href="/assets/favicon.ico">
  <meta name="apple-mobile-web-app-title" content="PomBase">
  <meta name="application-name" content="PomBase">
"##,
            title, title, config.database_name, title
    )
}

fn gene_summary(config: &Config, gene_details: &GeneDetails) -> String {
    let mut summ = String::new();

    summ += "
\n";
    if let Some(ref name) = gene_details.name {
        summ += &format!("
Gene standard name

{}
\n",  name);
    }
    summ += &format!("
Systematic ID

{}
\n",  gene_details.uniquename);

    if let Some(gene_organism) = config.organism_by_taxonid(gene_details.taxonid) {
        summ += &format!("
Organism

{}\n", gene_organism.scientific_name());

        if gene_organism.alternative_names.len() > 0 {
            summ += &format!(" ({})", gene_organism.alternative_names.join(", "));
        }
        summ += "
\n";
    }

    summ += "
\n";

    summ
}

fn get_annotations(ont_annotation_ids: &Vec<OntAnnotationId>,
                   gene_details: &GeneDetails) -> String {
    let mut ret = String::new();
    let mut references = HashSet::new();
    for ont_annotation_id in ont_annotation_ids {
        if let Some(annotation_details) = gene_details.annotation_details.get(ont_annotation_id) {
            if let Some(ref reference) = annotation_details.reference {
                references.insert(reference);
            }
        }
    }

    for reference in references {
        ret += &format!("<sect>{}</sect>\n", reference);
    }

    ret
}

fn gene_annotation(config: &Config, gene_details: &GeneDetails) -> String {
    let mut annotation_html = String::new();

    for (cv_name, term_annotations) in &gene_details.cv_annotations {
        let cv_config = config.cv_config_by_name(cv_name);
        let cv_display_name = cv_config.display_name;
        annotation_html += &format!("<sect>\n
{}
\n", cv_display_name);
        for term_annotation in term_annotations {
            let term_name =
                if let Some(term_short_opt) =
                    gene_details.terms_by_termid.get(&term_annotation.term) {
                        if let Some(term_short) = term_short_opt {
                            String::from(term_short.name.as_str())
                        } else {
                            String::from("(unknown term name)")
                        }
                    } else {
                        String::from("(unknown term name)")
                    };
            annotation_html += &format!("<sect>
{} - {}
\n{}</sect>\n",
                                        term_annotation.term,
                                        term_name,
                                        get_annotations(&term_annotation.annotations,
                                                        gene_details));
        }
        annotation_html += "</sect>\n";
    }

    annotation_html
}

fn gene_body(config: &Config, title: &str, gene_details: &GeneDetails) -> String {
    let mut body = String::new();

    body += &format!("
{}
\n", title);

    body += &format!("<sect>
Welcome to PomBase
\n
{}
</sect>\n",
                     config.site_description);

    body += &format!("<sect>
Gene summary
\n{}</sect>\n",
                     gene_summary(config, gene_details));

    body += &format!("<sect>
Annotation
\n{}</sect>\n",
                     gene_annotation(config, gene_details));
    body
}

pub fn render_simple_gene_page(config: &Config, gene_details: &GeneDetails) -> String  {
    let title = make_title(config, gene_details);

    format! ("
<!DOCTYPE html>

    {}

    {}

",
          gene_header(config, &title),
          gene_body(config, &title, gene_details))
}
<commit_msg>Add links to term and reference pages<commit_after>use std::collections::HashSet;

use crate::web::config::Config;
use crate::web::data::{GeneDetails, OntAnnotationId};

fn make_title(config: &Config, gene_details: &GeneDetails) -> String {
    let name_and_uniquename =
        if let Some(ref name) = gene_details.name {
            format!("{} ({})", name, gene_details.uniquename)
        } else {
            format!("{}", gene_details.uniquename)
        };

    let feature_type =
        if gene_details.feature_type.ends_with(" gene") {
            String::from(gene_details.feature_type.as_str())
        } else {
            format!("{} gene", gene_details.feature_type)
        };

    if let Some(ref product) = gene_details.product {
        format!("{} - {} {} - {}", config.database_name, feature_type,
                name_and_uniquename, product)
    } else {
        format!("{} - {} {}", config.database_name, feature_type, name_and_uniquename)
    }
}

fn gene_header(config: &Config, title: &str) -> String  {
    format!(r##"
  <meta charset="utf-8">
  <title>{}</title>
  <base href="/">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="title" content="{}">
  <meta name="author" content="{}">
  <meta name="description" content="{}">
  <meta name="google-site-verification" content="H8vhCdG7XsSbh-8f20VSipvu2PnZ22YSGZm81jE0-Pk" />
  <link rel="shortcut icon" href="/assets/favicon.ico">
  <meta name="apple-mobile-web-app-title" content="PomBase">
  <meta name="application-name" content="PomBase">
"##,
            title, title, config.database_name, title
    )
}

fn gene_summary(config: &Config, gene_details: &GeneDetails) -> String {
    let mut summ = String::new();

    summ += "
\n";
    if let Some(ref name) = gene_details.name {
        summ += &format!("
Gene standard name

{}
\n",  name);
    }
    summ += &format!("
Systematic ID

{}
\n",  gene_details.uniquename);

    if let Some(gene_organism) = config.organism_by_taxonid(gene_details.taxonid) {
        summ += &format!("
Organism

{}\n", gene_organism.scientific_name());

        if gene_organism.alternative_names.len() > 0 {
            summ += &format!(" ({})", gene_organism.alternative_names.join(", "));
        }
        summ += "
\n";
    }

    summ += "
\n";

    summ
}

fn get_annotations(ont_annotation_ids: &Vec<OntAnnotationId>,
                   gene_details: &GeneDetails) -> String {
    let mut ret = String::new();
    let mut references = HashSet::new();
    for ont_annotation_id in ont_annotation_ids {
        if let Some(annotation_details) = gene_details.annotation_details.get(ont_annotation_id) {
            if let Some(ref reference) = annotation_details.reference {
                references.insert(reference);
            }
        }
    }

    if references.len() > 0 {
        ret += "
References:
\n
";
        for reference in references {
            ret += &format!("
{}
\n", reference, reference);
        }
        ret += "
\n";
    }

    ret
}

fn gene_annotation(config: &Config, gene_details: &GeneDetails) -> String {
    let mut annotation_html = String::new();

    for (cv_name, term_annotations) in &gene_details.cv_annotations {
        let cv_config = config.cv_config_by_name(cv_name);
        let cv_display_name = cv_config.display_name;
        annotation_html += &format!("<sect>\n
{}
\n", cv_display_name);
        for term_annotation in term_annotations {
            let term_name =
                if let Some(term_short_opt) =
                    gene_details.terms_by_termid.get(&term_annotation.term) {
                        if let Some(term_short) = term_short_opt {
                            String::from(term_short.name.as_str())
                        } else {
                            String::from("(unknown term name)")
                        }
                    } else {
                        String::from("(unknown term name)")
                    };
            annotation_html += &format!("<sect>
{} - \
{}
\n{}</sect>\n",
                                        term_annotation.term,
                                        term_annotation.term,
                                        term_annotation.term,
                                        term_name,
                                        get_annotations(&term_annotation.annotations,
                                                        gene_details));
        }
        annotation_html += "</sect>\n";
    }

    annotation_html
}

fn gene_body(config: &Config, title: &str, gene_details: &GeneDetails) -> String {
    let mut body = String::new();

    body += &format!("
{}
\n", title);

    body += &format!("<sect>
Welcome to PomBase
\n
{}
</sect>\n",
                     config.site_description);

    body += &format!("<sect>
Gene summary
\n{}</sect>\n",
                     gene_summary(config, gene_details));

    body += &format!("<sect>
Annotation
\n{}</sect>\n",
                     gene_annotation(config, gene_details));
    body
}

pub fn render_simple_gene_page(config: &Config, gene_details: &GeneDetails) -> String  {
    let title = make_title(config, gene_details);

    format! ("
<!DOCTYPE html>

    {}

    {}

",
          gene_header(config, &title),
          gene_body(config, &title, gene_details))
}
<|endoftext|>


<commit_before><commit_msg>Add configurable value sizes and specific command proportions to stress2<commit_after><|endoftext|>


<commit_before>//! A shared ordered log.

use std::rc::Rc;
use std::cell::RefCell;
use std::time::{Instant, Duration};
use std::collections::VecDeque;

use ::{communication::Allocate, ExchangeData, PartialOrder};
use ::scheduling::Scheduler;
use worker::Worker;
use dataflow::channels::pact::Exchange;
use dataflow::operators::generic::operator::source;
use dataflow::operators::generic::operator::Operator;
use scheduling::activate::Activator;

// A Sequencer needs all operators firing with high frequency, because
// it uses the timer to gauge progress. If other workers cease
// advancing their own capabilities, although they might receive a
// record they may not actually tick forward their own source clocks,
// and no one will actually form the sequence.
//
// A CatchupActivator is an activator with an optional timestamp
// attached. This allows us to represent a special state, where after
// receiving an action from another worker, each of the other workers
// will keep scheduling its source operator, until its capability
// timestamp exceeds the greatest timestamp that the sink has
// received.
//
// This allows operators to go quiet again until a new requests shows
// up. The operators lose the ability to confirm that nothing is
// scheduled for a particular time (they could request this with a
// no-op event bearing a timestamp), but everyone still sees the same
// sequence.
struct CatchupActivator {
    pub catchup_until: Option<Duration>,
    activator: Activator,
}

impl CatchupActivator {
    pub fn activate(&self) {
        self.activator.activate();
    }
}

/// Orders elements inserted across all workers.
///
/// A Sequencer allows each worker to insert into a consistent ordered
/// sequence that is seen by all workers in the same order.
pub struct Sequencer<T> {
    activator: Rc<RefCell<Option<CatchupActivator>>>,
    send: Rc<RefCell<VecDeque<T>>>, // proposed items.
    recv: Rc<RefCell<VecDeque<T>>>, // sequenced items.
}

impl<T: ExchangeData> Sequencer<T> {

    /// Creates a new Sequencer.
    ///
    /// The `timer` instant is used to synchronize the workers, who use this
    /// elapsed time as their timestamp. Elements are ordered by this time,
    /// and cannot be made visible until all workers have reached the time.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::time::{Instant, Duration};
    ///
    /// use timely::Configuration;
    /// use timely::synchronization::Sequencer;
    ///
    /// timely::execute(Configuration::Process(4), |worker| {
    ///     let timer = Instant::now();
    ///     let mut sequencer = Sequencer::new(worker, timer);
    ///
    ///     for round in 0 .. 10 {
    ///
    ///         // Sleep, and then send an announcement on wake-up.
    ///         std::thread::sleep(Duration::from_millis(1 + worker.index() as u64));
    ///         sequencer.push(format!("worker {:?}, round {:?}", worker.index(), round));
    ///
    ///         // Ensures the pushed string is sent.
    ///         worker.step();
    ///
    ///         // Read out received announcements.
    ///         while let Some(element) = sequencer.next() {
    ///             println!("{:?}:\tWorker {:?}:\t recv'd: {:?}", timer.elapsed(), worker.index(), element);
    ///         }
    ///     }
    /// }).expect("Timely computation did not complete correctly.");
    /// ```
    pub fn new<A: Allocate>(worker: &mut Worker<A>, timer: Instant) -> Self {
        Sequencer::preloaded(worker, timer, VecDeque::new())
    }

    /// Creates a new Sequencer preloaded with a queue of
    /// elements.
    pub fn preloaded<A: Allocate>(worker: &mut Worker<A>, timer: Instant, preload: VecDeque<T>) -> Self {

        let send: Rc<RefCell<VecDeque<T>>> = Rc::new(RefCell::new(VecDeque::new()));
        let recv = Rc::new(RefCell::new(preload));
        let send_weak = Rc::downgrade(&send);
        let recv_weak = Rc::downgrade(&recv);

        // The SequenceInput activator will be held by the sequencer,
        // by the operator itself, and by the sink operator. We can
        // only initialize the activator once we obtain the operator
        // address.
        let activator = Rc::new(RefCell::new(None));
        let activator_source = activator.clone();
        let activator_sink = activator.clone();

        // build a dataflow used to serialize and circulate commands
        worker.dataflow::<Duration,_,_>(move |dataflow| {

            let scope = dataflow.clone();
            let peers = dataflow.peers();

            let mut recvd = Vec::new();
            let mut vector = Vec::new();

            // monotonic counter to maintain per-worker total order.
            let mut counter = 0;

            // a source that attempts to pull from `recv` and produce commands for everyone
            source(dataflow, "SequenceInput", move |capability, info| {

                // intialize activator, now that we have the address
                activator_source
                    .borrow_mut()
                    .replace(CatchupActivator {
                        activator: scope.activator_for(&info.address[..]),
                        catchup_until: None,
                    });

                // so we can drop, if input queue vanishes.
                let mut capability = Some(capability);

                // closure broadcasts any commands it grabs.
                move |output| {

                    if let Some(send_queue) = send_weak.upgrade() {

                        // capability *should* still be non-None.
                        let capability = capability.as_mut().expect("Capability unavailable");

                        // downgrade capability to current time.
                        capability.downgrade(&timer.elapsed());

                        // drain and broadcast `send`.
                        let mut session = output.session(&capability);
                        let mut borrow = send_queue.borrow_mut();
                        for element in borrow.drain(..) {
                            for worker_index in 0 .. peers {
                                session.give((worker_index, counter, element.clone()));
                            }
                            counter += 1;
                        }

                        let mut activator_borrow = activator_source.borrow_mut();
                        let mut activator = activator_borrow.as_mut().unwrap();

                        if let Some(t) = activator.catchup_until {
                            if capability.time().less_than(&t) {
                                activator.activate();
                            } else {
                                activator.catchup_until = None;
                            }
                        }
                    } else {
                        println!("Shutting down sequencer");
                        capability = None;
                    }
                }
            })
            .sink(
                Exchange::new(|x: &(usize, usize, T)| x.0 as u64),
                "SequenceOutput",
                move |input| {

                    // grab each command and queue it up
                    input.for_each(|time, data| {
                        data.swap(&mut vector);
                        for (worker, counter, element) in vector.drain(..) {
                            recvd.push(((time.time().clone(), worker, counter), element));
                        }
                    });

                    recvd.sort_by(|x,y| x.0.cmp(&y.0));

                    if let Some(last) = recvd.last() {
                        let mut activator_borrow = activator_sink.borrow_mut();
                        let mut activator = activator_borrow.as_mut().unwrap();

                        activator.catchup_until = Some((last.0).0);
                        activator.activate();
                    }

                    // determine how many (which) elements to read from `recvd`.
                    let count = recvd.iter().filter(|&((ref time, _, _), _)| !input.frontier().less_equal(time)).count();
                    let iter = recvd.drain(..count);

                    if let Some(recv_queue) = recv_weak.upgrade() {
                        recv_queue.borrow_mut().extend(iter.map(|(_,elem)| elem));
                    }
                }
            );
        });

        Sequencer { activator, send, recv, }
    }

    /// Adds an element to the shared log.
    pub fn push(&mut self, element: T) {
        self.send.borrow_mut().push_back(element);
        self.activator.borrow_mut().as_mut().unwrap().activate();
    }
}

impl<T> Iterator for Sequencer<T> {
    type Item = T;
    fn next(&mut self) -> Option<T> {
        self.recv.borrow_mut().pop_front()
    }
}

// We should activate on drop, as this will cause the source to drop its capability.
impl<T> Drop for Sequencer<T> {
    fn drop(&mut self) {
        self.activator
            .borrow()
            .as_ref()
            .expect("Sequencer.activator unavailable")
            .activate()
    }
}<commit_msg>remove println<commit_after>//! A shared ordered log.

use std::rc::Rc;
use std::cell::RefCell;
use std::time::{Instant, Duration};
use std::collections::VecDeque;

use ::{communication::Allocate, ExchangeData, PartialOrder};
use ::scheduling::Scheduler;
use worker::Worker;
use dataflow::channels::pact::Exchange;
use dataflow::operators::generic::operator::source;
use dataflow::operators::generic::operator::Operator;
use scheduling::activate::Activator;

// A Sequencer needs all operators firing with high frequency, because
// it uses the timer to gauge progress. If other workers cease
// advancing their own capabilities, although they might receive a
// record they may not actually tick forward their own source clocks,
// and no one will actually form the sequence.
//
// A CatchupActivator is an activator with an optional timestamp
// attached. This allows us to represent a special state, where after
// receiving an action from another worker, each of the other workers
// will keep scheduling its source operator, until its capability
// timestamp exceeds the greatest timestamp that the sink has
// received.
//
// This allows operators to go quiet again until a new requests shows
// up. The operators lose the ability to confirm that nothing is
// scheduled for a particular time (they could request this with a
// no-op event bearing a timestamp), but everyone still sees the same
// sequence.
struct CatchupActivator {
    pub catchup_until: Option<Duration>,
    activator: Activator,
}

impl CatchupActivator {
    pub fn activate(&self) {
        self.activator.activate();
    }
}

/// Orders elements inserted across all workers.
///
/// A Sequencer allows each worker to insert into a consistent ordered
/// sequence that is seen by all workers in the same order.
pub struct Sequencer<T> {
    activator: Rc<RefCell<Option<CatchupActivator>>>,
    send: Rc<RefCell<VecDeque<T>>>, // proposed items.
    recv: Rc<RefCell<VecDeque<T>>>, // sequenced items.
}

impl<T: ExchangeData> Sequencer<T> {

    /// Creates a new Sequencer.
    ///
    /// The `timer` instant is used to synchronize the workers, who use this
    /// elapsed time as their timestamp. Elements are ordered by this time,
    /// and cannot be made visible until all workers have reached the time.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::time::{Instant, Duration};
    ///
    /// use timely::Configuration;
    /// use timely::synchronization::Sequencer;
    ///
    /// timely::execute(Configuration::Process(4), |worker| {
    ///     let timer = Instant::now();
    ///     let mut sequencer = Sequencer::new(worker, timer);
    ///
    ///     for round in 0 .. 10 {
    ///
    ///         // Sleep, and then send an announcement on wake-up.
    ///         std::thread::sleep(Duration::from_millis(1 + worker.index() as u64));
    ///         sequencer.push(format!("worker {:?}, round {:?}", worker.index(), round));
    ///
    ///         // Ensures the pushed string is sent.
    ///         worker.step();
    ///
    ///         // Read out received announcements.
    ///         while let Some(element) = sequencer.next() {
    ///             println!("{:?}:\tWorker {:?}:\t recv'd: {:?}", timer.elapsed(), worker.index(), element);
    ///         }
    ///     }
    /// }).expect("Timely computation did not complete correctly.");
    /// ```
    pub fn new<A: Allocate>(worker: &mut Worker<A>, timer: Instant) -> Self {
        Sequencer::preloaded(worker, timer, VecDeque::new())
    }

    /// Creates a new Sequencer preloaded with a queue of
    /// elements.
    pub fn preloaded<A: Allocate>(worker: &mut Worker<A>, timer: Instant, preload: VecDeque<T>) -> Self {

        let send: Rc<RefCell<VecDeque<T>>> = Rc::new(RefCell::new(VecDeque::new()));
        let recv = Rc::new(RefCell::new(preload));
        let send_weak = Rc::downgrade(&send);
        let recv_weak = Rc::downgrade(&recv);

        // The SequenceInput activator will be held by the sequencer,
        // by the operator itself, and by the sink operator. We can
        // only initialize the activator once we obtain the operator
        // address.
        let activator = Rc::new(RefCell::new(None));
        let activator_source = activator.clone();
        let activator_sink = activator.clone();

        // build a dataflow used to serialize and circulate commands
        worker.dataflow::<Duration,_,_>(move |dataflow| {

            let scope = dataflow.clone();
            let peers = dataflow.peers();

            let mut recvd = Vec::new();
            let mut vector = Vec::new();

            // monotonic counter to maintain per-worker total order.
            let mut counter = 0;

            // a source that attempts to pull from `recv` and produce commands for everyone
            source(dataflow, "SequenceInput", move |capability, info| {

                // intialize activator, now that we have the address
                activator_source
                    .borrow_mut()
                    .replace(CatchupActivator {
                        activator: scope.activator_for(&info.address[..]),
                        catchup_until: None,
                    });

                // so we can drop, if input queue vanishes.
                let mut capability = Some(capability);

                // closure broadcasts any commands it grabs.
                move |output| {

                    if let Some(send_queue) = send_weak.upgrade() {

                        // capability *should* still be non-None.
                        let capability = capability.as_mut().expect("Capability unavailable");

                        // downgrade capability to current time.
                        capability.downgrade(&timer.elapsed());

                        // drain and broadcast `send`.
                        let mut session = output.session(&capability);
                        let mut borrow = send_queue.borrow_mut();
                        for element in borrow.drain(..) {
                            for worker_index in 0 .. peers {
                                session.give((worker_index, counter, element.clone()));
                            }
                            counter += 1;
                        }

                        let mut activator_borrow = activator_source.borrow_mut();
                        let mut activator = activator_borrow.as_mut().unwrap();

                        if let Some(t) = activator.catchup_until {
                            if capability.time().less_than(&t) {
                                activator.activate();
                            } else {
                                activator.catchup_until = None;
                            }
                        }
                    } else {
                        capability = None;
                    }
                }
            })
            .sink(
                Exchange::new(|x: &(usize, usize, T)| x.0 as u64),
                "SequenceOutput",
                move |input| {

                    // grab each command and queue it up
                    input.for_each(|time, data| {
                        data.swap(&mut vector);
                        for (worker, counter, element) in vector.drain(..) {
                            recvd.push(((time.time().clone(), worker, counter), element));
                        }
                    });

                    recvd.sort_by(|x,y| x.0.cmp(&y.0));

                    if let Some(last) = recvd.last() {
                        let mut activator_borrow = activator_sink.borrow_mut();
                        let mut activator = activator_borrow.as_mut().unwrap();

                        activator.catchup_until = Some((last.0).0);
                        activator.activate();
                    }

                    // determine how many (which) elements to read from `recvd`.
                    let count = recvd.iter().filter(|&((ref time, _, _), _)| !input.frontier().less_equal(time)).count();
                    let iter = recvd.drain(..count);

                    if let Some(recv_queue) = recv_weak.upgrade() {
                        recv_queue.borrow_mut().extend(iter.map(|(_,elem)| elem));
                    }
                }
            );
        });

        Sequencer { activator, send, recv, }
    }

    /// Adds an element to the shared log.
    pub fn push(&mut self, element: T) {
        self.send.borrow_mut().push_back(element);
        self.activator.borrow_mut().as_mut().unwrap().activate();
    }
}

impl<T> Iterator for Sequencer<T> {
    type Item = T;
    fn next(&mut self) -> Option<T> {
        self.recv.borrow_mut().pop_front()
    }
}

// We should activate on drop, as this will cause the source to drop its capability.
impl<T> Drop for Sequencer<T> {
    fn drop(&mut self) {
        self.activator
            .borrow()
            .as_ref()
            .expect("Sequencer.activator unavailable")
            .activate()
    }
}<|endoftext|>


<commit_before>/// Map representation

extern mod std;

enum square {
    bot,
    wall,
    rock,
    lambda,
    closed_lift,
    open_lift,
    earth,
    empty
}

impl square: to_str::ToStr {
    fn to_str() -> ~str {
        match self {
          bot => { ~"R" }
          wall => { ~"#" }
          rock => { ~"*" }
          lambda => { ~"\\" }
          closed_lift => { ~"L" }
          open_lift => { ~"O" }
          earth => { ~"." }
          empty => { ~" " }
        }
    }
}

fn square_from_char(c: char) -> square {
    match c  {
      'R'  => { bot }
      '#'  => { wall }
      '*'  => { rock }
      '\\' => { lambda }
      'L'  => { closed_lift }
      'O'  => { open_lift }
      '.'  => { earth }
      ' '  => { empty }
      _ => {
        #error("invalid square: %?", c);
        fail
      }
    }
}

fn read_board_grid<rdr: Owned io::Reader>(+in: rdr) -> ~[~[square]] {
    let in = in as io::Reader;
    let mut grid = ~[];
    for in.each_line |line| {
        let mut row = ~[];
        for line.each_char |c| {
            vec::push(row, square_from_char(c))
        }
        vec::push(grid, row)
    }
    let width = grid[0].len();
    for grid.each |row| { assert row.len() == width }
    grid
}

mod test {
    #[legacy_exports];
    #[test]
    fn trivial_to_str() {
        assert lambda.to_str() == "\\"
    }

    #[test]
    fn read_simple_board() {
        let s = #include_str("./maps/contest1.map");
        io::with_str_reader(s, read_board_grid)
    }
}

fn main() {}
<commit_msg>Fix test/run-pass/issue-2904<commit_after>/// Map representation

use io::ReaderUtil;

extern mod std;

enum square {
    bot,
    wall,
    rock,
    lambda,
    closed_lift,
    open_lift,
    earth,
    empty
}

impl square: to_str::ToStr {
    fn to_str() -> ~str {
        match self {
          bot => { ~"R" }
          wall => { ~"#" }
          rock => { ~"*" }
          lambda => { ~"\\" }
          closed_lift => { ~"L" }
          open_lift => { ~"O" }
          earth => { ~"." }
          empty => { ~" " }
        }
    }
}

fn square_from_char(c: char) -> square {
    match c  {
      'R'  => { bot }
      '#'  => { wall }
      '*'  => { rock }
      '\\' => { lambda }
      'L'  => { closed_lift }
      'O'  => { open_lift }
      '.'  => { earth }
      ' '  => { empty }
      _ => {
        #error("invalid square: %?", c);
        fail
      }
    }
}

fn read_board_grid<rdr: Owned io::Reader>(+in: rdr) -> ~[~[square]] {
    let in = in as io::Reader;
    let mut grid = ~[];
    for in.each_line |line| {
        let mut row = ~[];
        for str::each_char(line) |c| {
            vec::push(row, square_from_char(c))
        }
        vec::push(grid, row)
    }
    let width = grid[0].len();
    for grid.each |row| { assert row.len() == width }
    grid
}

mod test {
    #[legacy_exports];
    #[test]
    fn trivial_to_str() {
        assert lambda.to_str() == "\\"
    }

    #[test]
    fn read_simple_board() {
        let s = #include_str("./maps/contest1.map");
        io::with_str_reader(s, read_board_grid)
    }
}

fn main() {}
<|endoftext|>


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

// Check that merely have lifetime parameters is not
// enough for trans to consider this as non-monomorphic,
// which led to various assertions and failures in turn.

struct S<'self> {
    v: &'self int
}

fn f<'lt>(_s: &S<'lt>) {}

fn main() {
    f(& S { v: &42 });
}
<commit_msg>Cheat and temporarily work around a pretty-printer bug that will go away with the new region syntax.<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Check that merely having lifetime parameters is not
// enough for trans to consider this as non-monomorphic,
// which led to various assertions and failures in turn.

struct S<'self> {
    v: &'self int
}

fn f<'lt>(_s: &'lt S<'lt>) {}

fn main() {
    f(& S { v: &42 });
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::ptr;
use std::sync::Arc;
use smallvec::SmallVec;

use command_buffer::pool::CommandPool;
use command_buffer::sys::UnsafeCommandBuffer;
use device::Queue;
use sync::Fence;
use sync::PipelineStages;
use sync::Semaphore;

use check_errors;
use vk;
use VulkanObject;
use VulkanPointers;
use SynchronizedVulkanObject;

/// Trait for objects that represent commands ready to be executed by the GPU.
pub unsafe trait CommandBuffer {
    /// Submits the command buffer.
    ///
    /// Note that since submitting has a fixed overhead, you should try, if possible, to submit
    /// multiple command buffers at once instead.
    ///
    /// This is a simple shortcut for creating a `Submit` object.
    #[inline]
    fn submit(self, queue: &Arc<Queue>) where Self: Sized {
        Submit::new().add(self).submit(queue)
    }

    /// Type of the pool that was used to allocate the command buffer.
    type Pool: CommandPool;

    /// Iterator that returns the list of semaphores to wait upon before the command buffer is
    /// submitted.
    type SemaphoresWaitIterator: Iterator<Item = (Arc<Semaphore>, PipelineStages)>;

    /// Iterator that returns the list of semaphores to signal after the command buffer has
    /// finished execution.
    type SemaphoresSignalIterator: Iterator<Item = Arc<Semaphore>>;

    /// Returns the inner object.
    fn inner(&self) -> &UnsafeCommandBuffer<Self::Pool>;

    /// Called slightly before the command buffer is submitted. Signals the command buffers that it
    /// is going to be submitted on the given queue. The function must return the list of
    /// semaphores to wait upon and transitions to perform.
    ///
    /// The `fence` parameter is a closure that can be used to pull a fence if required. If a fence
    /// is pulled, it is guaranteed that it will be signaled after the command buffer ends.
    ///
    /// # Safety for the caller
    ///
    /// This function must only be called if there's actually a submission that follows. If a
    /// fence is pulled, then it must eventually be signaled. All the semaphores that are waited
    /// upon must become unsignaled, and all the semaphores that are supposed to be signaled must
    /// become signaled.
    ///
    /// This function is supposed to be called only by vulkano's internals. It is recommended
    /// that you never call it.
    ///
    /// # Safety for the implementation
    ///
    /// The implementation must ensure that the command buffer doesn't get destroyed before the
    /// fence is signaled, or before a fence of a later submission to the same queue is signaled.
    ///
    unsafe fn on_submit<F>(&self, queue_family: u32, queue_within_family: u32, fence: F)
                           -> SubmitInfo<Self::SemaphoresWaitIterator,
                                         Self::SemaphoresSignalIterator>
        where F: FnOnce() -> Arc<Fence>;
}

/// Information about how the submitting function should synchronize the submission.
pub struct SubmitInfo<Swi, Ssi> {
    /// List of semaphores to wait upon before the command buffer starts execution.
    pub semaphores_wait: Swi,
    /// List of semaphores to signal after the command buffer has finished.
    pub semaphores_signal: Ssi,
    /// Pipeline barrier to execute on the queue and immediately before the command buffer.
    /// Ignored if empty.
    pub pre_pipeline_barrier: PipelineBarrierBuilder,
    /// Pipeline barrier to execute on the queue and immediately after the command buffer.
    /// Ignored if empty.
    pub post_pipeline_barrier: PipelineBarrierBuilder,
}

#[derive(Debug, Copy, Clone)]
pub struct Submit<L> {
    list: L,
}

impl Submit<()> {
    /// Builds an empty submission list.
    #[inline]
    pub fn new() -> Submit<()> {
        Submit { list: () }
    }
}

impl<L> Submit<L> where L: SubmitList {
    /// Adds a command buffer to submit to the list.
    ///
    /// In the Vulkan API, a submission is divided into batches that each contain one or more
    /// command buffers. Vulkano will automatically determine which command buffers can be grouped
    /// into the same batch.
    #[inline]
    pub fn add<C>(self, command_buffer: C) -> Submit<(C, L)> where C: CommandBuffer {
        Submit { list: (command_buffer, self.list) }
    }

    /// Submits the list of command buffers.
    pub fn submit(self, queue: &Arc<Queue>) {
        let SubmitListOpaque { fence, wait_semaphores, wait_stages, command_buffers,
                               signal_semaphores, mut submits }
                             = self.list.infos(queue.family().id(), queue.id_within_family());

        // Filling the pointers inside `submits`.
        unsafe {
            debug_assert_eq!(wait_semaphores.len(), wait_stages.len());

            let mut next_wait = 0;
            let mut next_cb = 0;
            let mut next_signal = 0;

            for submit in submits.iter_mut() {
                debug_assert!(submit.waitSemaphoreCount as usize + next_wait as usize <=
                              wait_semaphores.len());
                debug_assert!(submit.commandBufferCount as usize + next_cb as usize <=
                              command_buffers.len());
                debug_assert!(submit.signalSemaphoreCount as usize + next_signal as usize <=
                              signal_semaphores.len());

                submit.pWaitSemaphores = wait_semaphores.as_ptr().offset(next_wait);
                submit.pWaitDstStageMask = wait_stages.as_ptr().offset(next_wait);
                submit.pCommandBuffers = command_buffers.as_ptr().offset(next_cb);
                submit.pSignalSemaphores = signal_semaphores.as_ptr().offset(next_signal);

                next_wait += submit.waitSemaphoreCount as isize;
                next_cb += submit.commandBufferCount as isize;
                next_signal += submit.signalSemaphoreCount as isize;
            }

            debug_assert_eq!(next_wait as usize, wait_semaphores.len());
            debug_assert_eq!(next_wait as usize, wait_stages.len());
            debug_assert_eq!(next_cb as usize, command_buffers.len());
            debug_assert_eq!(next_signal as usize, signal_semaphores.len());
        }

        unsafe {
            let vk = queue.device().pointers();
            let queue = queue.internal_object_guard();
            let fence = fence.as_ref().map(|f| f.internal_object()).unwrap_or(0);
            check_errors(vk.QueueSubmit(*queue, submits.len() as u32, submits.as_ptr(),
                                        fence)).unwrap();        // TODO: handle errors (trickier than it looks)
        }
    }
}

/* TODO: All that stuff below is undocumented */

pub struct SubmitListOpaque {
    fence: Option<Arc<Fence>>,
    wait_semaphores: SmallVec<[vk::Semaphore; 16]>,
    wait_stages: SmallVec<[vk::PipelineStageFlags; 16]>,
    command_buffers: SmallVec<[vk::CommandBuffer; 16]>,
    signal_semaphores: SmallVec<[vk::Semaphore; 16]>,
    submits: SmallVec<[vk::SubmitInfo; 8]>,
}

pub unsafe trait SubmitList {
    fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque;
}

unsafe impl SubmitList for () {
    fn infos(self, _: u32, _: u32) -> SubmitListOpaque {
        SubmitListOpaque {
            fence: None,
            wait_semaphores: SmallVec::new(),
            wait_stages: SmallVec::new(),
            command_buffers: SmallVec::new(),
            signal_semaphores: SmallVec::new(),
            submits: SmallVec::new(),
        }
    }
}

unsafe impl<C, R> SubmitList for (C, R) where C: CommandBuffer, R: SubmitList {
    fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque {
        // TODO: attempt to group multiple submits into one when possible

        let (current, rest) = self;

        let mut infos = rest.infos(queue_family, queue_within_family);
        let device = current.inner().device().clone();
        let current_infos = unsafe { current.on_submit(queue_family, queue_within_family, || {
            if let Some(fence) = infos.fence.as_ref() {
                return fence.clone();
            }

            let new_fence = Fence::new(device);
            infos.fence = Some(new_fence.clone());
            new_fence
        })};

        // TODO: not implemented ; where to store the created command buffers?
        assert!(current_infos.pre_pipeline_barrier.is_empty());
        assert!(current_infos.post_pipeline_barrier.is_empty());

        let mut new_submit = vk::SubmitInfo {
            sType: vk::STRUCTURE_TYPE_SUBMIT_INFO,
            pNext: ptr::null(),
            waitSemaphoreCount: 0,
            pWaitSemaphores: ptr::null(),
            pWaitDstStageMask: ptr::null(),
            commandBufferCount: 1,
            pCommandBuffers: ptr::null(),
            signalSemaphoreCount: 0,
            pSignalSemaphores: ptr::null(),
        };

        for (semaphore, stage) in current_infos.semaphores_wait {
            infos.wait_semaphores.push(semaphore.internal_object());
            infos.wait_stages.push(stage.into());
            new_submit.waitSemaphoreCount += 1;
        }

        for semaphore in current_infos.semaphores_signal {
            infos.signal_semaphores.push(semaphore.internal_object());
            new_submit.signalSemaphoreCount += 1;
        }

        infos.command_buffers.push(current.inner().internal_object());

        infos.submits.push(new_submit);

        infos
    }
}
<commit_msg>Return a Submission object when submitting<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::ptr;
use std::sync::Arc;
use smallvec::SmallVec;

use command_buffer::pool::CommandPool;
use command_buffer::sys::PipelineBarrierBuilder;
use command_buffer::sys::UnsafeCommandBuffer;
use device::Queue;
use sync::Fence;
use sync::PipelineStages;
use sync::Semaphore;

use check_errors;
use vk;
use VulkanObject;
use VulkanPointers;
use SynchronizedVulkanObject;

/// Trait for objects that represent commands ready to be executed by the GPU.
pub unsafe trait CommandBuffer {
    /// Submits the command buffer.
    ///
    /// Note that since submitting has a fixed overhead, you should try, if possible, to submit
    /// multiple command buffers at once instead.
    ///
    /// This is a simple shortcut for creating a `Submit` object.
    #[inline]
    fn submit(self, queue: &Arc<Queue>) -> Submission where Self: Sized {
        Submit::new().add(self).submit(queue)
    }

    /// Type of the pool that was used to allocate the command buffer.
    type Pool: CommandPool;

    /// Iterator that returns the list of semaphores to wait upon before the command buffer is
    /// submitted.
    type SemaphoresWaitIterator: Iterator<Item = (Arc<Semaphore>, PipelineStages)>;

    /// Iterator that returns the list of semaphores to signal after the command buffer has
    /// finished execution.
    type SemaphoresSignalIterator: Iterator<Item = Arc<Semaphore>>;

    /// Returns the inner object.
    fn inner(&self) -> &UnsafeCommandBuffer<Self::Pool>;

    /// Called slightly before the command buffer is submitted. Signals the command buffers that it
    /// is going to be submitted on the given queue. The function must return the list of
    /// semaphores to wait upon and transitions to perform.
    ///
    /// The `fence` parameter is a closure that can be used to pull a fence if required. If a fence
    /// is pulled, it is guaranteed that it will be signaled after the command buffer ends.
    ///
    /// # Safety for the caller
    ///
    /// This function must only be called if there's actually a submission that follows. If a
    /// fence is pulled, then it must eventually be signaled. All the semaphores that are waited
    /// upon must become unsignaled, and all the semaphores that are supposed to be signaled must
    /// become signaled.
    ///
    /// This function is supposed to be called only by vulkano's internals. It is recommended
    /// that you never call it.
    ///
    /// # Safety for the implementation
    ///
    /// The implementation must ensure that the command buffer doesn't get destroyed before the
    /// fence is signaled, or before a fence of a later submission to the same queue is signaled.
    ///
    unsafe fn on_submit<F>(&self, queue_family: u32, queue_within_family: u32, fence: F)
                           -> SubmitInfo<Self::SemaphoresWaitIterator,
                                         Self::SemaphoresSignalIterator>
        where F: FnOnce() -> Arc<Fence>;
}

/// Information about how the submitting function should synchronize the submission.
pub struct SubmitInfo<Swi, Ssi> {
    /// List of semaphores to wait upon before the command buffer starts execution.
    pub semaphores_wait: Swi,
    /// List of semaphores to signal after the command buffer has finished.
    pub semaphores_signal: Ssi,
    /// Pipeline barrier to execute on the queue and immediately before the command buffer.
    /// Ignored if empty.
    pub pre_pipeline_barrier: PipelineBarrierBuilder,
    /// Pipeline barrier to execute on the queue and immediately after the command buffer.
    /// Ignored if empty.
    pub post_pipeline_barrier: PipelineBarrierBuilder,
}

// TODO: docs
// # Leak safety
//
// The `Submission` object can hold borrows of command buffers. In order for it to be safe to leak
// a `Submission`, the borrowed object themselves must be protected by a fence.
#[must_use]
pub struct Submission {
    keep_alive: SmallVec<[Arc<KeepAlive>; 4]>,
}

trait KeepAlive {}
impl<T> KeepAlive for T {}

#[derive(Debug, Copy, Clone)]
pub struct Submit<L> {
    list: L,
}

impl Submit<()> {
    /// Builds an empty submission list.
    #[inline]
    pub fn new() -> Submit<()> {
        Submit { list: () }
    }
}

impl<L> Submit<L> where L: SubmitList {
    /// Adds a command buffer to submit to the list.
    ///
    /// In the Vulkan API, a submission is divided into batches that each contain one or more
    /// command buffers. Vulkano will automatically determine which command buffers can be grouped
    /// into the same batch.
    #[inline]
    pub fn add<C>(self, command_buffer: C) -> Submit<(C, L)> where C: CommandBuffer {
        Submit { list: (command_buffer, self.list) }
    }

    /// Submits the list of command buffers.
    pub fn submit(self, queue: &Arc<Queue>) -> Submission {
        let SubmitListOpaque { fence, wait_semaphores, wait_stages, command_buffers,
                               signal_semaphores, mut submits, keep_alive }
                             = self.list.infos(queue.family().id(), queue.id_within_family());

        // Filling the pointers inside `submits`.
        unsafe {
            debug_assert_eq!(wait_semaphores.len(), wait_stages.len());

            let mut next_wait = 0;
            let mut next_cb = 0;
            let mut next_signal = 0;

            for submit in submits.iter_mut() {
                debug_assert!(submit.waitSemaphoreCount as usize + next_wait as usize <=
                              wait_semaphores.len());
                debug_assert!(submit.commandBufferCount as usize + next_cb as usize <=
                              command_buffers.len());
                debug_assert!(submit.signalSemaphoreCount as usize + next_signal as usize <=
                              signal_semaphores.len());

                submit.pWaitSemaphores = wait_semaphores.as_ptr().offset(next_wait);
                submit.pWaitDstStageMask = wait_stages.as_ptr().offset(next_wait);
                submit.pCommandBuffers = command_buffers.as_ptr().offset(next_cb);
                submit.pSignalSemaphores = signal_semaphores.as_ptr().offset(next_signal);

                next_wait += submit.waitSemaphoreCount as isize;
                next_cb += submit.commandBufferCount as isize;
                next_signal += submit.signalSemaphoreCount as isize;
            }

            debug_assert_eq!(next_wait as usize, wait_semaphores.len());
            debug_assert_eq!(next_wait as usize, wait_stages.len());
            debug_assert_eq!(next_cb as usize, command_buffers.len());
            debug_assert_eq!(next_signal as usize, signal_semaphores.len());
        }

        unsafe {
            let vk = queue.device().pointers();
            let queue = queue.internal_object_guard();
            let fence = fence.as_ref().map(|f| f.internal_object()).unwrap_or(0);
            check_errors(vk.QueueSubmit(*queue, submits.len() as u32, submits.as_ptr(),
                                        fence)).unwrap();        // TODO: handle errors (trickier than it looks)
        }

        Submission {
            keep_alive: keep_alive,
        }
    }
}

/* TODO: All that stuff below is undocumented */

pub struct SubmitListOpaque {
    fence: Option<Arc<Fence>>,
    wait_semaphores: SmallVec<[vk::Semaphore; 16]>,
    wait_stages: SmallVec<[vk::PipelineStageFlags; 16]>,
    command_buffers: SmallVec<[vk::CommandBuffer; 16]>,
    signal_semaphores: SmallVec<[vk::Semaphore; 16]>,
    submits: SmallVec<[vk::SubmitInfo; 8]>,
    keep_alive: SmallVec<[Arc<KeepAlive>; 4]>,
}

pub unsafe trait SubmitList {
    fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque;
}

unsafe impl SubmitList for () {
    fn infos(self, _: u32, _: u32) -> SubmitListOpaque {
        SubmitListOpaque {
            fence: None,
            wait_semaphores: SmallVec::new(),
            wait_stages: SmallVec::new(),
            command_buffers: SmallVec::new(),
            signal_semaphores: SmallVec::new(),
            submits: SmallVec::new(),
            keep_alive: SmallVec::new(),
        }
    }
}

unsafe impl<C, R> SubmitList for (C, R) where C: CommandBuffer, R: SubmitList {
    fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque {
        // TODO: attempt to group multiple submits into one when possible

        let (current, rest) = self;

        let mut infos = rest.infos(queue_family, queue_within_family);
        let device = current.inner().device().clone();
        let current_infos = unsafe { current.on_submit(queue_family, queue_within_family, || {
            if let Some(fence) = infos.fence.as_ref() {
                return fence.clone();
            }

            let new_fence = Fence::new(device);
            infos.fence = Some(new_fence.clone());
            new_fence
        })};

        // TODO: not implemented ; where to store the created command buffers?
        assert!(current_infos.pre_pipeline_barrier.is_empty());
        assert!(current_infos.post_pipeline_barrier.is_empty());

        let mut new_submit = vk::SubmitInfo {
            sType: vk::STRUCTURE_TYPE_SUBMIT_INFO,
            pNext: ptr::null(),
            waitSemaphoreCount: 0,
            pWaitSemaphores: ptr::null(),
            pWaitDstStageMask: ptr::null(),
            commandBufferCount: 1,
            pCommandBuffers: ptr::null(),
            signalSemaphoreCount: 0,
            pSignalSemaphores: ptr::null(),
        };

        for (semaphore, stage) in current_infos.semaphores_wait {
            infos.wait_semaphores.push(semaphore.internal_object());
            infos.wait_stages.push(stage.into());
            infos.keep_alive.push(semaphore);
            new_submit.waitSemaphoreCount += 1;
        }

        for semaphore in current_infos.semaphores_signal {
            infos.signal_semaphores.push(semaphore.internal_object());
            infos.keep_alive.push(semaphore);
            new_submit.signalSemaphoreCount += 1;
        }

        infos.command_buffers.push(current.inner().internal_object());

        infos.submits.push(new_submit);

        infos
    }
}
<|endoftext|>


<commit_before>use super::StockPrice;
use utils::console::*;

use hyper::Client;
use hyper::header::Connection;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;
use select::document::Document;
use select::predicate::{Predicate, Attr, Class, Name};
use serde_urlencoded;
use std::io::Read;

static BASE_URL: &'static str = "https://www.comdirect.de/inf/search/all.html";

error_chain! {
    errors {
        ComdirectScrapingFailed(info: String) {
            description("Did not find information in HTML document")
            display("Did not find {} in HTML document", info)
        }
    }
}

pub fn scrape_stock_price(search: String) -> Result<StockPrice> {
    let parameters = &[("SEARCH_VALUE", search) ];
    let parameters_enc = serde_urlencoded::to_string(&parameters)
        .chain_err(|| "Could not encode URL parameters")?;
    let url = format!("{}?{}", BASE_URL, parameters_enc);

    let body = get_stock_page(&url).unwrap();
    let stock_price = parse_stock_price(&body)?;

    Ok(stock_price)
}

fn get_stock_page(url: &str) -> Result<Vec<u8>> {
    let ssl = NativeTlsClient::new().chain_err(|| "Could not create TLS client")?;
    let connector = HttpsConnector::new(ssl);
    let client = Client::with_connector(connector);
    info("Sending search request ...");
    let mut response = client.get(url).header(Connection::close()).send()
        .chain_err(|| "Could not send request")?;

    let mut body = Vec::new();
    let size = response.read_to_end(&mut body)
        .chain_err(|| "Could not read response body")?;
    info(format!("Received {} bytes body.", size));

    Ok(body)
}

fn parse_stock_price(body: &[u8]) -> Result<StockPrice> {
    let document = Document::from_read(body).chain_err(|| "Could not parse HTML in response body")?;

    let no_exact_match = document.find(Class("Informer")).nth(0).is_some();
    if no_exact_match {
        bail!("Could not find exact match for your search");
    }

    let name = document.find(Name("h1")).nth(0)
        .ok_or_else(|| ErrorKind::ComdirectScrapingFailed("name".to_string()))?.text();
    let price_currency = document.find(Class("price")).nth(0)
        .ok_or_else(|| ErrorKind::ComdirectScrapingFailed("stock price".to_string()))?.text();
    let date = document.find(Attr("id", "keyelement_kurs_update").descendant(Class("date"))).last()
        .ok_or_else(|| ErrorKind::ComdirectScrapingFailed("stock price date".to_string()))?.text();
    let wkn = document.find(Class("clearfix").descendant(Name("table")).descendant(Name("tr")).descendant(Class("right"))).last()
        .ok_or_else(|| ErrorKind::ComdirectScrapingFailed("stock WKN".to_string()))?.text();

    let mut pc_split = price_currency.split_whitespace();
    let price = pc_split.nth(0)
        .ok_or_else(|| ErrorKind::ComdirectScrapingFailed("price".to_string()))?
        .trim()
        .replace(",", ".") // decimal separation
        .parse()
        .chain_err(|| ErrorKind::ComdirectScrapingFailed("price".to_string()))?;
    let currency = pc_split.nth(0).ok_or_else(|| ErrorKind::ComdirectScrapingFailed("currency".to_string()))?;

    let stock_price = StockPrice {
        name: name.trim().to_string(),
        wkn: wkn.trim().to_string(),
        date: date.to_string(),
        price: price,
        currency: currency.trim().to_string(),
    };

    Ok(stock_price)
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::Read;
    use std::fs::File;

    fn get_stock_page(file: &str) -> Result<Vec<u8>> {
        let mut f = File::open(file).unwrap();
        let mut buffer = Vec::new();
        f.read_to_end(&mut buffer).unwrap();

        Ok(buffer)
    }

    #[test]
    fn test_parse_ok() {
        let body = get_stock_page("test/data/stocks/deutsche_bank.html").unwrap();
        let db = parse_stock_price(&body).unwrap();

        assert_eq!(db.name, "Deutsche Bank AG Namens-Aktien o.N.");
        assert_eq!(db.wkn, "514000");
        assert_eq!(db.date, "10.03.17\u{a0}\u{a0}17:35:07\u{a0}Uhr");
        assert_eq!(db.price, 18.26f32);
        assert_eq!(db.currency, "EUR");
    }

    #[test]
    fn test_parse_no_exact_match() {
        let body = get_stock_page("test/data/stocks/no_exact_match.html").unwrap();
        let db = parse_stock_price(&body);

        assert!(db.is_err());
    }
}
<commit_msg>Fix and tests for comdirect scraping<commit_after>use super::StockPrice;
use utils::console::*;

use hyper::Client;
use hyper::header::Connection;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;
use select::document::Document;
use select::predicate::{Predicate, Attr, Class, Name};
use serde_urlencoded;
use std::io::Read;

static BASE_URL: &'static str = "https://www.comdirect.de/inf/search/all.html";

error_chain! {
    errors {
        ComdirectScrapingFailed(info: String) {
            description("Did not find information in HTML document")
            display("Did not find {} in HTML document", info)
        }
        ComdirectSearchResultNotUnique {
            description("The search did not returned an unique result")
            display("The search did not returned an unique result")
        }
    }
}

pub fn scrape_stock_price(search: String) -> Result<StockPrice> {
    let parameters = &[("SEARCH_VALUE", search) ];
    let parameters_enc = serde_urlencoded::to_string(&parameters)
        .chain_err(|| "Could not encode URL parameters")?;
    let url = format!("{}?{}", BASE_URL, parameters_enc);

    let body = get_stock_page(&url).unwrap();
    let stock_price = parse_stock_price(&body)?;

    Ok(stock_price)
}

fn get_stock_page(url: &str) -> Result<Vec<u8>> {
    let ssl = NativeTlsClient::new().chain_err(|| "Could not create TLS client")?;
    let connector = HttpsConnector::new(ssl);
    let client = Client::with_connector(connector);
    info("Sending search request ...");
    let mut response = client.get(url).header(Connection::close()).send()
        .chain_err(|| "Could not send request")?;

    let mut body = Vec::new();
    let size = response.read_to_end(&mut body)
        .chain_err(|| "Could not read response body")?;
    info(format!("Received {} bytes body.", size));

    Ok(body)
}

fn parse_stock_price(body: &[u8]) -> Result<StockPrice> {
    let document = Document::from_read(body).chain_err(|| "Could not parse HTML in response body")?;

    let no_exact_match = document.find(Class("Informer")).nth(0).is_some();
    if no_exact_match {
        bail!(ErrorKind::ComdirectSearchResultNotUnique);
    }

    let name = document.find(Name("h1")).nth(0)
        .ok_or_else(|| ErrorKind::ComdirectScrapingFailed("name".to_string()))?.text();
    let price_currency = document.find(Class("price")).nth(0)
        .ok_or_else(|| ErrorKind::ComdirectScrapingFailed("stock price".to_string()))?.text();
    let date = document.find(Attr("id", "keyelement_kurs_update").descendant(Class("date"))).last()
        .ok_or_else(|| ErrorKind::ComdirectScrapingFailed("stock price date".to_string()))?.text();
    let wkn = document.find(Class("clearfix").descendant(Name("table")).descendant(Name("tr")).descendant(Class("right"))).last()
        .ok_or_else(|| ErrorKind::ComdirectScrapingFailed("stock WKN".to_string()))?.text();

    let mut pc_split = price_currency.split_whitespace();
    let price = pc_split.nth(0)
        .ok_or_else(|| ErrorKind::ComdirectScrapingFailed("price".to_string()))?
        .trim()
        .replace(",", ".") // decimal separation
        .parse()
        .chain_err(|| ErrorKind::ComdirectScrapingFailed("price".to_string()))?;
    let currency = pc_split.nth(0).ok_or_else(|| ErrorKind::ComdirectScrapingFailed("currency".to_string()))?;

    let stock_price = StockPrice {
        name: name.trim().to_string(),
        wkn: wkn.trim().to_string(),
        date: date.to_string(),
        price: price,
        currency: currency.trim().to_string(),
    };

    Ok(stock_price)
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::Read;
    use std::fs::File;

    fn get_stock_page(file: &str) -> Result<Vec<u8>> {
        let mut f = File::open(file).unwrap();
        let mut buffer = Vec::new();
        f.read_to_end(&mut buffer).unwrap();

        Ok(buffer)
    }

    #[test]
    fn test_parse_file_ok() {
        let body = get_stock_page("test/data/stocks/deutsche_bank.html").unwrap();
        let db = parse_stock_price(&body).unwrap();

        assert_eq!(db.name, "Deutsche Bank AG Namens-Aktien o.N.");
        assert_eq!(db.wkn, "514000");
        assert_eq!(db.date, "10.03.17\u{a0}\u{a0}17:35:07\u{a0}Uhr");
        assert_eq!(db.price, 18.26f32);
        assert_eq!(db.currency, "EUR");
    }

    #[test]
    fn test_parse_file_no_exact_match() {
        let body = get_stock_page("test/data/stocks/no_exact_match.html").unwrap();
        let db = parse_stock_price(&body);

        assert!(db.is_err());
    }

    #[test]
    fn test_parse_online_ok() {
        ::utils::console::init(::config::Verbosity::QUIET);
        let db = scrape_stock_price("Deutsche Bank".to_string()).unwrap();

        assert_eq!(db.name, "Deutsche Bank AG Namens-Aktien o.N.");
        assert_eq!(db.wkn, "514000");
        assert!(db.price > 0.00f32);
        assert_eq!(db.currency, "EUR");
    }

    #[test]
    fn test_parse_online_no_exact_match() {
        ::utils::console::init(::config::Verbosity::QUIET);
        let result = scrape_stock_price("Deutsche".to_string());

        // TODO: This needs to be nicer.
        let result_is_not_unique = match result.unwrap_err() {
            Error(ErrorKind::ComdirectSearchResultNotUnique, _) => true,
            _ => false
        };
        assert!(result_is_not_unique);
    }
 }
<|endoftext|>


<commit_before>//! Calculate alignments with a generalized variant of the Smith Waterman algorithm.
//! Complexity: O(n * m) for strings of length m and n.
//!
//! # Example
//!
//! ```
//! use bio::alignment::pairwise::Aligner;
//! use bio::alignment::AlignmentOperation::{Match, Subst, Ins, Del};
//! let x = b"ACCGTGGAT";
//! let y = b"AAAAACCGTTGAT";
//! let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
//! let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
//! let alignment = aligner.semiglobal(x, y);
//! assert_eq!(alignment.i, 4);
//! assert_eq!(alignment.j, 0);
//! assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
//! ```

use std::i32;
use std::iter::repeat;
use std::cmp::max;

use alignment::{Alignment, AlignmentOperation};
use bitencoding::BitEnc;

struct AlignmentState {
    m: usize,
    n: usize,
    best: i32,
}

macro_rules! align {
    (
        $obj:ident, $state:ident,
        $init:block, $inner:block, $outer:block, $ret:block
    ) => (
        {
            let (mut best, mut best_i, mut best_j) = (0, 0, 0);
            let mut col = 0;

            for i in 1..$n+1 {
                col = i % 2;
                let prev = 1 - col;

                // init code
                $init

                let b = y[i - 1];
                let mut score = 0i32;
                for j in 1..$m+1 {
                    let a = x[j - 1];

                    // score for deletion
                    let d_score = max(
                        $obj.S[prev][j] + $obj.gap_open,
                        $obj.D[prev][j] + $obj.gap_extend
                    );
                    // score for insertion
                    let i_score = max(
                        $obj.S[col][j-1] + $obj.gap_open,
                        $obj.I[col][j-1] + $obj.gap_extend
                    );
                    // score for substitution
                    score = $obj.S[prev][j-1] + ($obj.score)(a, b);

                    if d_score > score {
                        score = d_score;
                        $obj.traceback.del(i, j);
                    }
                    else if i_score > score {
                        score = i_score;
                        $obj.traceback.ins(i, j);
                    }
                    else {
                        $obj.traceback.subst(i, j);
                    }

                    // inner code
                    $inner

                    $obj.S[col][j] = score;
                    $obj.D[col][j] = d_score;
                    $obj.I[col][j] = i_score;
                }

                // outer code
                $outer
            }

            // return code
            $ret
        }
    );
}

#[allow(non_snake_case)]
pub struct Aligner<F> where F: Fn(u8, u8) -> i32 {
    S: [Vec<i32>; 2],
    I: [Vec<i32>; 2],
    D: [Vec<i32>; 2],
    traceback: Traceback,
    gap_open: i32,
    gap_extend: i32,
    score: F
}

impl<F> Aligner<F> where F: Fn(u8, u8) -> i32 {
    /// Create new aligner instance. The size hints help to
    /// avoid unnecessary memory allocations.
    ///
    /// # Arguments
    ///
    /// * `m` - the expected size of x
    /// * `n` - the expected size of y
    /// * `gap_open` - the score for opening a gap (should be negative)
    /// * `gap_extend` - the score for extending a gap (should be negative)
    /// * `score` - function that returns the score for substitutions
    ///
    pub fn with_capacity(m: usize, n: usize, gap_open: i32, gap_extend: i32, score: F) -> Self {
        let get_vec = |&:| Vec::with_capacity(m + 1);
        Aligner {
            S: [get_vec(), get_vec()],
            I: [get_vec(), get_vec()],
            D: [get_vec(), get_vec()],
            traceback: Traceback::with_capacity(m, n),
            gap_open: gap_open,
            gap_extend: gap_extend,
            score: score
        }
    }

    fn init(&mut self, m: usize, global: bool) {
        // set minimum score to -inf, and allow to add gap_extend
        // without overflow
        let min_score = i32::MIN - self.gap_extend;
        for k in 0..2us {
            self.S[k].clear();
            self.I[k].clear();
            self.D[k].clear();
            self.I[k].extend(repeat(min_score).take(m + 1));
            self.D[k].extend(repeat(min_score).take(m + 1));
            if global {
                let ref mut s = self.S[k];
                let mut score = self.gap_open;
                for _ in 0..m+1 {
                    s.push(score);
                    score += self.gap_extend;
                }
            }
            else {
                self.S[k].extend(repeat(0).take(m + 1))
            }
        }
    }

    /// Calculate global alignment.
    pub fn global(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        let (m, n) = (x.len(), y.len());
        self.init(m, true);
        self.traceback.init(m, n, true);

        align!(
            self, m, n,
            {
                self.S[col][0] = self.gap_open + (i as i32 - 1) * self.gap_extend;
                self.traceback.del(i, 0);
            }, {}, {},
            {
                let score = self.S[col][m];
                self.traceback.get_alignment(n, m, x, y, score)
            }
        );
    }

    /// Calculate semiglobal alignment.
    pub fn semiglobal(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        let (m, n) = (x.len(), y.len());
        self.init(m, false);
        self.traceback.init(m, n, false);

        align!(
            self, m, n,
            { self.S[col][0] = 0; },
            {},
            {
                if score > best {
                    best = score;
                    best_i = i;
                    best_j = m;
                }
            },
            { self.traceback.get_alignment(best_i, best_j, x, y, best) }
        );
    }

    /// Calculate local alignment.
    pub fn local(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        let (m, n) = (x.len(), y.len());
        self.init(m, false);
        self.traceback.init(m, n, false);

        align!(
            self, m, n,
            { self.S[col][0] = 0; },
            {
                if score < 0 {
                    self.traceback.start(i, j);
                    score = 0;
                }
                else if score > best {
                    best = score;
                    best_i = i;
                    best_j = j;
                }
            },
            {},
            { self.traceback.get_alignment(best_i, best_j, x, y, best) }
        );
    }
}

struct Traceback {
    matrix: Vec<BitEnc>
}

static TBSTART: u8 = 0b00;
static TBSUBST: u8 = 0b01;
static TBINS: u8   = 0b10;
static TBDEL: u8   = 0b11;

impl Traceback {

    fn with_capacity(m: usize, n: usize) -> Self {
        let mut matrix = Vec::with_capacity(n+1);
        for _ in 0..n+1 {
            matrix.push(BitEnc::with_capacity(2, m + 1));
        }
        Traceback {
            matrix: matrix
        }
    }

    fn init(&mut self, m: usize, n: usize, global: bool) {
        if global {
            // set the first cell to start, the rest to deletions
            for i in 0..n+1 {
                self.matrix[i].clear();
                self.matrix[i].push_values(m + 1, TBDEL);
            }
            self.matrix[0].set(0, TBSTART);
        }
        else {
            for i in 0..n+1 {
                self.matrix[i].clear();
                self.matrix[i].push_values(m + 1, TBSTART);
            }
        }
    }

    fn start(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBSTART);
    }

    fn subst(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBSUBST);
    }

    fn del(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBDEL);
    }

    fn ins(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBINS);
    }

    fn is_subst(&self, i: usize, j: usize) -> bool {
        self.matrix[i].get(j).unwrap() == TBSUBST
    }

    fn is_del(&self, i: usize, j: usize) -> bool {
        self.matrix[i].get(j).unwrap() == TBDEL
    }

    fn is_ins(&self, i: usize, j: usize) -> bool {
        self.matrix[i].get(j).unwrap() == TBINS
    }

    fn get_alignment(&self, mut i: usize, mut j: usize, x: &[u8], y: &[u8], score: i32) -> Alignment {
        let mut ops = Vec::with_capacity(x.len());

        loop {
            let (ii, jj, op) = if self.is_subst(i, j) {
                let op = if y[i-1] == x[j-1] {
                    AlignmentOperation::Match
                }
                else {
                    AlignmentOperation::Subst
                };
                (i - 1, j - 1, op)
            }
            else if self.is_del(i, j) {
                (i - 1, j, AlignmentOperation::Del)
            }
            else if self.is_ins(i, j) {
                (i, j - 1, AlignmentOperation::Ins)
            } else {
                // reached alignment start
                break;
            };
            ops.push(op);
            i = ii;
            j = jj;
        }

        ops.reverse();
        Alignment { i: i, j: j, operations: ops, score: score}
    }
}

#[cfg(test)]
mod tests {
    use super::Aligner;
    use alignment::AlignmentOperation::{Match, Subst, Del};

    #[test]
    fn test_semiglobal() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.semiglobal(x, y);
        assert_eq!(alignment.i, 4);
        assert_eq!(alignment.j, 0);
        assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }

    #[test]
    fn test_local() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.local(x, y);
        assert_eq!(alignment.i, 4);
        assert_eq!(alignment.j, 0);
        assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }

    #[test]
    fn test_global() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.global(x, y);
        assert_eq!(alignment.i, 0);
        assert_eq!(alignment.j, 0);
        assert_eq!(alignment.operations, [Del, Del, Del, Del, Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }
}
<commit_msg>Minor.<commit_after>//! Calculate alignments with a generalized variant of the Smith Waterman algorithm.
//! Complexity: O(n * m) for strings of length m and n.
//!
//! # Example
//!
//! ```
//! use bio::alignment::pairwise::Aligner;
//! use bio::alignment::AlignmentOperation::{Match, Subst, Ins, Del};
//! let x = b"ACCGTGGAT";
//! let y = b"AAAAACCGTTGAT";
//! let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
//! let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
//! let alignment = aligner.semiglobal(x, y);
//! assert_eq!(alignment.i, 4);
//! assert_eq!(alignment.j, 0);
//! assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
//! ```

use std::i32;
use std::iter::repeat;
use std::cmp::max;

use alignment::{Alignment, AlignmentOperation};
use bitencoding::BitEnc;

macro_rules! align {
    (
        $obj:ident, $m:ident, $n:ident, $i: ident, $j:ident,
        $init:block, $inner:block, $outer:block, $ret:block
    ) => (
        {
            $obj.best = 0;
            $obj.best_i = 0;
            $obj.best_j = 0;

            let mut col = 0;

            for $i in 1..$n+1 {
                col = i % 2;
                let prev = 1 - col;

                // init code
                $init

                let b = y[i - 1];
                let mut score = 0i32;
                for $j in 1..$m+1 {
                    let a = x[j - 1];

                    // score for deletion
                    let d_score = max(
                        $obj.S[prev][j] + $obj.gap_open,
                        $obj.D[prev][j] + $obj.gap_extend
                    );
                    // score for insertion
                    let i_score = max(
                        $obj.S[col][j-1] + $obj.gap_open,
                        $obj.I[col][j-1] + $obj.gap_extend
                    );
                    // score for substitution
                    score = $obj.S[prev][j-1] + ($obj.score)(a, b);

                    if d_score > score {
                        score = d_score;
                        $obj.traceback.del(i, j);
                    }
                    else if i_score > score {
                        score = i_score;
                        $obj.traceback.ins(i, j);
                    }
                    else {
                        $obj.traceback.subst(i, j);
                    }

                    // inner code
                    $inner

                    $obj.S[col][j] = score;
                    $obj.D[col][j] = d_score;
                    $obj.I[col][j] = i_score;
                }

                // outer code
                $outer
            }

            // return code
            $ret
        }
    );
}

#[allow(non_snake_case)]
pub struct Aligner<F> where F: Fn(u8, u8) -> i32 {
    S: [Vec<i32>; 2],
    I: [Vec<i32>; 2],
    D: [Vec<i32>; 2],
    traceback: Traceback,
    gap_open: i32,
    gap_extend: i32,
    score: F,
}

impl<F> Aligner<F> where F: Fn(u8, u8) -> i32 {
    /// Create new aligner instance. The size hints help to
    /// avoid unnecessary memory allocations.
    ///
    /// # Arguments
    ///
    /// * `m` - the expected size of x
    /// * `n` - the expected size of y
    /// * `gap_open` - the score for opening a gap (should be negative)
    /// * `gap_extend` - the score for extending a gap (should be negative)
    /// * `score` - function that returns the score for substitutions
    ///
    pub fn with_capacity(m: usize, n: usize, gap_open: i32, gap_extend: i32, score: F) -> Self {
        let get_vec = |&:| Vec::with_capacity(m + 1);
        Aligner {
            S: [get_vec(), get_vec()],
            I: [get_vec(), get_vec()],
            D: [get_vec(), get_vec()],
            traceback: Traceback::with_capacity(m, n),
            gap_open: gap_open,
            gap_extend: gap_extend,
            score: score
        }
    }

    fn init(&mut self, m: usize, global: bool) {
        // set minimum score to -inf, and allow to add gap_extend
        // without overflow
        let min_score = i32::MIN - self.gap_extend;
        for k in 0..2us {
            self.S[k].clear();
            self.I[k].clear();
            self.D[k].clear();
            self.I[k].extend(repeat(min_score).take(m + 1));
            self.D[k].extend(repeat(min_score).take(m + 1));
            if global {
                let ref mut s = self.S[k];
                let mut score = self.gap_open;
                for _ in 0..m+1 {
                    s.push(score);
                    score += self.gap_extend;
                }
            }
            else {
                self.S[k].extend(repeat(0).take(m + 1))
            }
        }
    }

    /// Calculate global alignment.
    pub fn global(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        let (m, n) = (x.len(), y.len());
        self.init(m, true);
        self.traceback.init(m, n, true);

        align!(
            self, m, n, i, j,
            {
                self.S[col][0] = self.gap_open + (i as i32 - 1) * self.gap_extend;
                self.traceback.del(i, 0);
            }, {}, {},
            {
                let score = self.S[col][m];
                self.traceback.get_alignment(n, m, x, y, score)
            }
        );
    }

    /// Calculate semiglobal alignment.
    pub fn semiglobal(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        let (m, n) = (x.len(), y.len());
        self.init(m, false);
        self.traceback.init(m, n, false);

        align!(
            self, m, n, i, j,
            { self.S[col][0] = 0; },
            {},
            {
                if score > self.best {
                    self.best = score;
                    self.best_i = i;
                    self.best_j = m;
                }
            },
            { self.traceback.get_alignment(self.best_i, self.best_j, x, y, self.best) }
        );
    }

    /// Calculate local alignment.
    pub fn local(&mut self, x: &[u8], y: &[u8]) -> Alignment {
        let (m, n) = (x.len(), y.len());
        self.init(m, false);
        self.traceback.init(m, n, false);

        align!(
            self, m, n, i, j,
            { self.S[col][0] = 0; },
            {
                if score < 0 {
                    self.traceback.start(i, j);
                    score = 0;
                }
                else if score > best {
                    best = score;
                    best_i = i;
                    best_j = j;
                }
            },
            {},
            { self.traceback.get_alignment(best_i, best_j, x, y, best) }
        );
    }
}

struct Traceback {
    matrix: Vec<BitEnc>
}

static TBSTART: u8 = 0b00;
static TBSUBST: u8 = 0b01;
static TBINS: u8   = 0b10;
static TBDEL: u8   = 0b11;

impl Traceback {

    fn with_capacity(m: usize, n: usize) -> Self {
        let mut matrix = Vec::with_capacity(n+1);
        for _ in 0..n+1 {
            matrix.push(BitEnc::with_capacity(2, m + 1));
        }
        Traceback {
            matrix: matrix
        }
    }

    fn init(&mut self, m: usize, n: usize, global: bool) {
        if global {
            // set the first cell to start, the rest to deletions
            for i in 0..n+1 {
                self.matrix[i].clear();
                self.matrix[i].push_values(m + 1, TBDEL);
            }
            self.matrix[0].set(0, TBSTART);
        }
        else {
            for i in 0..n+1 {
                self.matrix[i].clear();
                self.matrix[i].push_values(m + 1, TBSTART);
            }
        }
    }

    fn start(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBSTART);
    }

    fn subst(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBSUBST);
    }

    fn del(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBDEL);
    }

    fn ins(&mut self, i: usize, j: usize) {
        self.matrix[i].set(j, TBINS);
    }

    fn is_subst(&self, i: usize, j: usize) -> bool {
        self.matrix[i].get(j).unwrap() == TBSUBST
    }

    fn is_del(&self, i: usize, j: usize) -> bool {
        self.matrix[i].get(j).unwrap() == TBDEL
    }

    fn is_ins(&self, i: usize, j: usize) -> bool {
        self.matrix[i].get(j).unwrap() == TBINS
    }

    fn get_alignment(&self, mut i: usize, mut j: usize, x: &[u8], y: &[u8], score: i32) -> Alignment {
        let mut ops = Vec::with_capacity(x.len());

        loop {
            let (ii, jj, op) = if self.is_subst(i, j) {
                let op = if y[i-1] == x[j-1] {
                    AlignmentOperation::Match
                }
                else {
                    AlignmentOperation::Subst
                };
                (i - 1, j - 1, op)
            }
            else if self.is_del(i, j) {
                (i - 1, j, AlignmentOperation::Del)
            }
            else if self.is_ins(i, j) {
                (i, j - 1, AlignmentOperation::Ins)
            } else {
                // reached alignment start
                break;
            };
            ops.push(op);
            i = ii;
            j = jj;
        }

        ops.reverse();
        Alignment { i: i, j: j, operations: ops, score: score}
    }
}

#[cfg(test)]
mod tests {
    use super::Aligner;
    use alignment::AlignmentOperation::{Match, Subst, Del};

    #[test]
    fn test_semiglobal() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.semiglobal(x, y);
        assert_eq!(alignment.i, 4);
        assert_eq!(alignment.j, 0);
        assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }

    #[test]
    fn test_local() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.local(x, y);
        assert_eq!(alignment.i, 4);
        assert_eq!(alignment.j, 0);
        assert_eq!(alignment.operations, [Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }

    #[test]
    fn test_global() {
        let x = b"ACCGTGGAT";
        let y = b"AAAAACCGTTGAT";
        let score = |&: a: u8, b: u8| if a == b {1i32} else {-1i32};
        let mut aligner = Aligner::with_capacity(x.len(), y.len(), -5, -1, score);
        let alignment = aligner.global(x, y);
        assert_eq!(alignment.i, 0);
        assert_eq!(alignment.j, 0);
        assert_eq!(alignment.operations, [Del, Del, Del, Del, Match, Match, Match, Match, Match, Subst, Match, Match, Match]);
    }
}
<|endoftext|>