<commit_before>use regex::Regex;
use reqwest;
use serde_json;

use web::data::{SolrTermSummary, SolrReferenceSummary};
use web::config::Config;

pub struct Search {
    solr_url: String,
    close_synonym_boost: f32,
    distant_synonym_boost: f32,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponse {
    pub docs: Vec<SolrTermSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponseContainer {
    pub response: SolrTermResponse,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub response: SolrRefResponse,
}

impl Search {
    pub fn new(config: &Config) -> Search {
        Search {
            solr_url: config.server.solr_url.clone(),
            close_synonym_boost: config.server.close_synonym_boost,
            distant_synonym_boost: config.server.distant_synonym_boost,
        }
    }

    fn get_query_part(&self, words: &[String]) -> String {
        let mut ret = String::new();

        let words_length = words.len();

        for (i, word) in words.iter().enumerate() {
            if i == words_length - 1 {
                ret += &format!("{} {}~0.8 {}*", word, word, word);
            } else {
                ret += &format!("{} {}~0.8 ", word, word);
            }
        }

        ret
    }

    pub fn term_complete(&self, cv_name: &str, q: &str)
                         -> Result<Vec<SolrTermSummary>, String>
    {
        let mut terms_url =
            self.solr_url.to_owned() + "/terms/select?wt=json&q=";

        let termid_re_string = r"^(?P<prefix>[\w_]+):(?P<accession>\d+)$";
        let termid_re = Regex::new(termid_re_string).unwrap();

        let parent_re_string = r"^\[".to_owned() + termid_re_string + r"\]$";
        let parent_re = Regex::new(&parent_re_string).unwrap();

        let maybe_captures = parent_re.captures(cv_name);

        if let Some(captures) = maybe_captures {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += &format!("(interesting_parents:{}\\:{} OR id:{}\\:{})",
                                  prefix, accession, prefix, accession);
        } else {
            terms_url += "cv_name:";
            terms_url += cv_name;
        }

        if let Some(captures) = termid_re.captures(q) {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += " AND id:";
            terms_url += prefix;
            terms_url += r"\:";
            terms_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            terms_url += " AND (name:(";

            let clean_words: Vec<String> =
                Regex::new(r"([\w\d\-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    terms_url += &format!("{} {}*", word, word);
                } else {
                    terms_url += &format!("{} ", word);
                }
            }

            let query_part = self.get_query_part(&clean_words);

            terms_url += &format!(") OR close_synonym_words:({})^{} OR distant_synonym_words:({})^{})",
                                  query_part, self.close_synonym_boost,
                                  query_part, self.distant_synonym_boost);
        }
        print!("Solr URL: {:?}\n", terms_url);

        match reqwest::get(&terms_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrTermResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

    pub fn ref_complete(&self, q: &str) -> Result<Vec<SolrReferenceSummary>, String> {
        let mut refs_url =
            self.solr_url.to_owned() + "/refs/select?wt=json&q=";

        let id_re_string = r"^(?:(?P<prefix>[\w_]+):\w*)?(?P<rest>\d\d\d\d\d+)$";
        let id_re = Regex::new(id_re_string).unwrap();

        if let Some(captures) = id_re.captures(q) {
            let mut prefix =
                if let Some(prefix_capture) = captures.name("prefix") {
                    prefix_capture.as_str()
                } else {
                    "PMID"
                };
            let accession = captures.name("rest").unwrap().as_str();
            refs_url += "id:";
            refs_url += prefix;
            refs_url += r"\:";
            refs_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            let clean_words: Vec<String> =
                Regex::new(r"([\w\d\-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();
            let mut clean_words_for_url = String::new();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    clean_words_for_url += &format!("{} {}*", word, word);
                } else {
                    clean_words_for_url += &format!("{} ", word);
                }
            }

            let url_parts =
                vec!["title", "citation", "authors", "authors_abbrev"]
                .iter()
                .map(|field_name| format!("{}:({})", field_name, clean_words_for_url))
                .collect::<Vec<String>>();

            refs_url += &url_parts.join(" OR ");

            for word in clean_words {
                if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                    if let Ok(num) = word.parse::<u32>() {
                        refs_url += &format!(" OR publication_year:{}^20", num);
                    }
                }
            }
        }

        print!("Solr refs URL: {:?}\n", refs_url);

        match reqwest::get(&refs_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrRefResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

}
<commit_msg>Fix matching of PMID:... IDs<commit_after>use regex::Regex;
use reqwest;
use serde_json;

use web::data::{SolrTermSummary, SolrReferenceSummary};
use web::config::Config;

pub struct Search {
    solr_url: String,
    close_synonym_boost: f32,
    distant_synonym_boost: f32,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponse {
    pub docs: Vec<SolrTermSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponseContainer {
    pub response: SolrTermResponse,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub response: SolrRefResponse,
}

impl Search {
    pub fn new(config: &Config) -> Search {
        Search {
            solr_url: config.server.solr_url.clone(),
            close_synonym_boost: config.server.close_synonym_boost,
            distant_synonym_boost: config.server.distant_synonym_boost,
        }
    }

    fn get_query_part(&self, words: &[String]) -> String {
        let mut ret = String::new();

        let words_length = words.len();

        for (i, word) in words.iter().enumerate() {
            if i == words_length - 1 {
                ret += &format!("{} {}~0.8 {}*", word, word, word);
            } else {
                ret += &format!("{} {}~0.8 ", word, word);
            }
        }

        ret
    }

    pub fn term_complete(&self, cv_name: &str, q: &str)
                         -> Result<Vec<SolrTermSummary>, String>
    {
        let mut terms_url =
            self.solr_url.to_owned() + "/terms/select?wt=json&q=";

        let termid_re_string = r"^(?P<prefix>[\w_]+):(?P<accession>\d+)$";
        let termid_re = Regex::new(termid_re_string).unwrap();

        let parent_re_string = r"^\[".to_owned() + termid_re_string + r"\]$";
        let parent_re = Regex::new(&parent_re_string).unwrap();

        let maybe_captures = parent_re.captures(cv_name);

        if let Some(captures) = maybe_captures {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += &format!("(interesting_parents:{}\\:{} OR id:{}\\:{})",
                                  prefix, accession, prefix, accession);
        } else {
            terms_url += "cv_name:";
            terms_url += cv_name;
        }

        if let Some(captures) = termid_re.captures(q) {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += " AND id:";
            terms_url += prefix;
            terms_url += r"\:";
            terms_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            terms_url += " AND (name:(";

            let clean_words: Vec<String> =
                Regex::new(r"([\w\d\-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    terms_url += &format!("{} {}*", word, word);
                } else {
                    terms_url += &format!("{} ", word);
                }
            }

            let query_part = self.get_query_part(&clean_words);

            terms_url += &format!(") OR close_synonym_words:({})^{} OR distant_synonym_words:({})^{})",
                                  query_part, self.close_synonym_boost,
                                  query_part, self.distant_synonym_boost);
        }
        print!("Solr URL: {:?}\n", terms_url);

        match reqwest::get(&terms_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrTermResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

    pub fn ref_complete(&self, q: &str) -> Result<Vec<SolrReferenceSummary>, String> {
        let mut refs_url =
            self.solr_url.to_owned() + "/refs/select?wt=json&q=";

        let id_re_string = r"^(?:(?P<prefix>[\w_]+):\s*)?(?P<rest>\d\d\d\d\d+)$";
        let id_re = Regex::new(id_re_string).unwrap();

        if let Some(captures) = id_re.captures(q) {
            let mut prefix =
                if let Some(prefix_capture) = captures.name("prefix") {
                    prefix_capture.as_str()
                } else {
                    "PMID"
                };
            let accession = captures.name("rest").unwrap().as_str();
            refs_url += "id:";
            refs_url += prefix;
            refs_url += r"\:";
            refs_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            let clean_words: Vec<String> =
                Regex::new(r"([\w\d\-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();
            let mut clean_words_for_url = String::new();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    clean_words_for_url += &format!("{} {}*", word, word);
                } else {
                    clean_words_for_url += &format!("{} ", word);
                }
            }

            let url_parts =
                vec!["title", "citation", "authors", "authors_abbrev"]
                .iter()
                .map(|field_name| format!("{}:({})", field_name, clean_words_for_url))
                .collect::<Vec<String>>();

            refs_url += &url_parts.join(" OR ");

            for word in clean_words {
                if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                    if let Ok(num) = word.parse::<u32>() {
                        refs_url += &format!(" OR publication_year:{}^20", num);
                    }
                }
            }
        }

        print!("Solr refs URL: {:?}\n", refs_url);

        match reqwest::get(&refs_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrRefResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

}
<|endoftext|>


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

use value::Value;
use relation::{Relation, IndexSelect, ViewSelect};
use primitive::{Primitive, resolve_as_scalar};
use std::cmp::{min, max};

#[derive(Clone, Debug)]
pub struct Table {
    pub insert: Option<IndexSelect>,
    pub remove: Option<IndexSelect>,
}

#[derive(Clone, Debug)]
pub struct Union {
    pub selects: Vec<IndexSelect>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ConstraintOp {
    EQ,
    NEQ,
    LT,
    GT,
    LTE,
    GTE,
}

#[derive(Clone, Debug)]
pub struct Constraint {
    pub left: usize,
    pub op: ConstraintOp,
    pub right: usize,
}

impl Constraint {
    fn is_satisfied_by(&self, state: &[&Value]) -> bool {
        match self.op {
            ConstraintOp::EQ => state[self.left] == state[self.right],
            ConstraintOp::NEQ => state[self.left] != state[self.right],
            ConstraintOp::LT => state[self.left] < state[self.right],
            ConstraintOp::GT => state[self.left] > state[self.right],
            ConstraintOp::LTE => state[self.left] <= state[self.right],
            ConstraintOp::GTE => state[self.left] >= state[self.right],
        }
    }
}

#[derive(Clone, Debug)]
pub enum JoinSource {
    Relation{
        input: usize
    },
    Primitive{
        primitive: Primitive,
        arguments: Vec<usize>,
    },
}

#[derive(Clone, Debug)]
pub struct Join {
    pub constants: Vec<Value>,
    pub sources: Vec<JoinSource>,
    pub constraints: Vec<Vec<Constraint>>,
    pub select: ViewSelect,
}

#[derive(Clone, Debug)]
pub struct Reducer {
    pub primitive: Primitive,
    pub arguments: Vec<usize>,
}

#[derive(Clone, Debug)]
pub struct Aggregate {
    pub constants: Vec<Value>,
    pub outer: IndexSelect,
    pub inner: IndexSelect,
    pub limit_from: Option<usize>,
    pub limit_to: Option<usize>,
    pub reducers: Vec<Reducer>,
    pub selects_inner: bool,
    pub select: ViewSelect,
}

#[derive(Clone, Debug)]
pub enum View {
    Table(Table),
    Union(Union),
    Join(Join),
    Aggregate(Aggregate),
}

fn push_all<'a>(state: &mut Vec<&'a Value>, input: &'a Vec<Value>) {
    for value in input.iter() {
        state.push(value);
    }
}

fn pop_all<'a>(state: &mut Vec<&'a Value>, input: &'a Vec<Value>) {
    for _ in input.iter() {
        state.pop();
    }
}

fn join_step<'a>(join: &'a Join, ix: usize, inputs: &[&'a Relation], state: &mut Vec<&'a Value>, index: &mut BTreeSet<Vec<Value>>) {
    if ix == join.sources.len() {
        index.insert(join.select.select(&state[..]));
    } else {
        match join.sources[ix] {
            JoinSource::Relation{input} => {
                for values in inputs[input].index.iter() {
                    push_all(state, values);
                    if join.constraints[ix].iter().all(|constraint| constraint.is_satisfied_by(&state[..])) {
                        join_step(join, ix+1, inputs, state, index)
                    }
                    pop_all(state, values);
                }
            }
            JoinSource::Primitive{ref primitive, ref arguments, ..} => {
                for values in primitive.eval_from_join(&arguments[..], &state[..]).into_iter() {
                    // promise the borrow checker that we will pop values before we exit this scope
                    let values = unsafe { ::std::mem::transmute::<&Vec<Value>, &'a Vec<Value>>(&values) };
                    push_all(state, values);
                    if join.constraints[ix].iter().all(|constraint| constraint.is_satisfied_by(&state[..])) {
                        join_step(join, ix+1, inputs, state, index)
                    }
                    pop_all(state, values);
                }
            }
        }
    }
}

fn aggregate_step<'a>(aggregate: &Aggregate, input_sets: &'a [&[Vec<Value>]], state: &mut Vec<&'a Value>, index: &mut BTreeSet<Vec<Value>>) {
    if input_sets.len() == 0 {
        index.insert(aggregate.select.select(&state[..]));
    } else {
        for values in input_sets[0].iter() {
            push_all(state, values);
            aggregate_step(aggregate, &input_sets[1..], state, index);
            pop_all(state, values);
        }
    }
}

impl View {
    pub fn run(&self, old_output: &Relation, inputs: &[&Relation]) -> Option<Relation> {
        match *self {
            View::Table(_) => None,
            View::Union(ref union) => {
                assert_eq!(union.selects.len(), inputs.len());
                let mut output = Relation::with_fields(old_output.fields.clone(), old_output.names.clone());
                for select in union.selects.iter() {
                    for values in select.select(&inputs[..]) {
                        output.index.insert(values);
                    }
                }
                Some(output)
            }
            View::Join(ref join) => {
                let mut output = Relation::with_fields(old_output.fields.clone(), old_output.names.clone());
                let mut tuples = Vec::with_capacity(join.sources.len());
                join_step(join, 0, inputs, &mut tuples, &mut output.index);
                Some(output)
            }
            View::Aggregate(ref aggregate) => {
                let mut output = Relation::with_fields(old_output.fields.clone(), old_output.names.clone());
                let mut outer = aggregate.outer.select(&inputs[..]);
                let mut inner = aggregate.inner.select(&inputs[..]);
                outer.sort();
                outer.dedup();
                inner.sort();
                let constants = &aggregate.constants[..];
                let mut group_start = 0;
                for outer_values in outer.into_iter() {
                    let mut group_end = group_start;
                    while (group_end < inner.len())
                    && (inner[group_end][0..outer_values.len()] == outer_values[..]) {
                        group_end += 1;
                    }
                    let (group, output_values) = {
                        let limit_from = match aggregate.limit_from {
                            None => group_start,
                            Some(ix) => group_start
                                + resolve_as_scalar(ix, constants, &outer_values[..]).as_usize(),
                        };
                        let limit_to = match aggregate.limit_to {
                            None => group_end,
                            Some(ix) => group_start
                                + resolve_as_scalar(ix, constants, &outer_values[..]).as_usize(),
                        };
                        let limit_from = min(max(limit_from, group_start), group_end);
                        let limit_to = min(max(limit_to, limit_from), group_end);
                        let group = &inner[limit_from..limit_to];
                        let output_values = aggregate.reducers.iter().map(|reducer| {
                            reducer.primitive.eval_from_aggregate(&reducer.arguments[..], constants, &outer_values[..], group)
                        }).collect::<Vec<_>>();
                        (group, output_values)
                    };
                    let mut output_sets = vec![];
                    if aggregate.selects_inner {
                        output_sets.push(group);
                    }
                    for output in output_values.iter() {
                        output_sets.push(output);
                    }
                    let mut state = outer_values.iter().collect();
                    aggregate_step(aggregate, &output_sets[..], &mut state, &mut output.index);
                    group_start = group_end;
                }
                Some(output)
            }
        }
    }
}<commit_msg>Have to fill in dummy values for inner when we dont select from it<commit_after>use std::collections::BTreeSet;

use value::Value;
use relation::{Relation, IndexSelect, ViewSelect};
use primitive::{Primitive, resolve_as_scalar};
use std::cmp::{min, max};

#[derive(Clone, Debug)]
pub struct Table {
    pub insert: Option<IndexSelect>,
    pub remove: Option<IndexSelect>,
}

#[derive(Clone, Debug)]
pub struct Union {
    pub selects: Vec<IndexSelect>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ConstraintOp {
    EQ,
    NEQ,
    LT,
    GT,
    LTE,
    GTE,
}

#[derive(Clone, Debug)]
pub struct Constraint {
    pub left: usize,
    pub op: ConstraintOp,
    pub right: usize,
}

impl Constraint {
    fn is_satisfied_by(&self, state: &[&Value]) -> bool {
        match self.op {
            ConstraintOp::EQ => state[self.left] == state[self.right],
            ConstraintOp::NEQ => state[self.left] != state[self.right],
            ConstraintOp::LT => state[self.left] < state[self.right],
            ConstraintOp::GT => state[self.left] > state[self.right],
            ConstraintOp::LTE => state[self.left] <= state[self.right],
            ConstraintOp::GTE => state[self.left] >= state[self.right],
        }
    }
}

#[derive(Clone, Debug)]
pub enum JoinSource {
    Relation{
        input: usize
    },
    Primitive{
        primitive: Primitive,
        arguments: Vec<usize>,
    },
}

#[derive(Clone, Debug)]
pub struct Join {
    pub constants: Vec<Value>,
    pub sources: Vec<JoinSource>,
    pub constraints: Vec<Vec<Constraint>>,
    pub select: ViewSelect,
}

#[derive(Clone, Debug)]
pub struct Reducer {
    pub primitive: Primitive,
    pub arguments: Vec<usize>,
}

#[derive(Clone, Debug)]
pub struct Aggregate {
    pub constants: Vec<Value>,
    pub outer: IndexSelect,
    pub inner: IndexSelect,
    pub limit_from: Option<usize>,
    pub limit_to: Option<usize>,
    pub reducers: Vec<Reducer>,
    pub selects_inner: bool,
    pub select: ViewSelect,
}

#[derive(Clone, Debug)]
pub enum View {
    Table(Table),
    Union(Union),
    Join(Join),
    Aggregate(Aggregate),
}

fn push_all<'a>(state: &mut Vec<&'a Value>, input: &'a Vec<Value>) {
    for value in input.iter() {
        state.push(value);
    }
}

fn pop_all<'a>(state: &mut Vec<&'a Value>, input: &'a Vec<Value>) {
    for _ in input.iter() {
        state.pop();
    }
}

fn join_step<'a>(join: &'a Join, ix: usize, inputs: &[&'a Relation], state: &mut Vec<&'a Value>, index: &mut BTreeSet<Vec<Value>>) {
    if ix == join.sources.len() {
        index.insert(join.select.select(&state[..]));
    } else {
        match join.sources[ix] {
            JoinSource::Relation{input} => {
                for values in inputs[input].index.iter() {
                    push_all(state, values);
                    if join.constraints[ix].iter().all(|constraint| constraint.is_satisfied_by(&state[..])) {
                        join_step(join, ix+1, inputs, state, index)
                    }
                    pop_all(state, values);
                }
            }
            JoinSource::Primitive{ref primitive, ref arguments, ..} => {
                for values in primitive.eval_from_join(&arguments[..], &state[..]).into_iter() {
                    // promise the borrow checker that we will pop values before we exit this scope
                    let values = unsafe { ::std::mem::transmute::<&Vec<Value>, &'a Vec<Value>>(&values) };
                    push_all(state, values);
                    if join.constraints[ix].iter().all(|constraint| constraint.is_satisfied_by(&state[..])) {
                        join_step(join, ix+1, inputs, state, index)
                    }
                    pop_all(state, values);
                }
            }
        }
    }
}

fn aggregate_step<'a>(aggregate: &Aggregate, input_sets: &'a [&[Vec<Value>]], state: &mut Vec<&'a Value>, index: &mut BTreeSet<Vec<Value>>) {
    if input_sets.len() == 0 {
        index.insert(aggregate.select.select(&state[..]));
    } else {
        for values in input_sets[0].iter() {
            push_all(state, values);
            aggregate_step(aggregate, &input_sets[1..], state, index);
            pop_all(state, values);
        }
    }
}

impl View {
    pub fn run(&self, old_output: &Relation, inputs: &[&Relation]) -> Option<Relation> {
        match *self {
            View::Table(_) => None,
            View::Union(ref union) => {
                assert_eq!(union.selects.len(), inputs.len());
                let mut output = Relation::with_fields(old_output.fields.clone(), old_output.names.clone());
                for select in union.selects.iter() {
                    for values in select.select(&inputs[..]) {
                        output.index.insert(values);
                    }
                }
                Some(output)
            }
            View::Join(ref join) => {
                let mut output = Relation::with_fields(old_output.fields.clone(), old_output.names.clone());
                let mut tuples = Vec::with_capacity(join.sources.len());
                join_step(join, 0, inputs, &mut tuples, &mut output.index);
                Some(output)
            }
            View::Aggregate(ref aggregate) => {
                let mut output = Relation::with_fields(old_output.fields.clone(), old_output.names.clone());
                let mut outer = aggregate.outer.select(&inputs[..]);
                let mut inner = aggregate.inner.select(&inputs[..]);
                outer.sort();
                outer.dedup();
                inner.sort();
                let constants = &aggregate.constants[..];
                let mut group_start = 0;
                for outer_values in outer.into_iter() {
                    let mut group_end = group_start;
                    while (group_end < inner.len())
                    && (inner[group_end][0..outer_values.len()] == outer_values[..]) {
                        group_end += 1;
                    }
                    let (group, output_values) = {
                        let limit_from = match aggregate.limit_from {
                            None => group_start,
                            Some(ix) => group_start
                                + resolve_as_scalar(ix, constants, &outer_values[..]).as_usize(),
                        };
                        let limit_to = match aggregate.limit_to {
                            None => group_end,
                            Some(ix) => group_start
                                + resolve_as_scalar(ix, constants, &outer_values[..]).as_usize(),
                        };
                        let limit_from = min(max(limit_from, group_start), group_end);
                        let limit_to = min(max(limit_to, limit_from), group_end);
                        let group = &inner[limit_from..limit_to];
                        let output_values = aggregate.reducers.iter().map(|reducer| {
                            reducer.primitive.eval_from_aggregate(&reducer.arguments[..], constants, &outer_values[..], group)
                        }).collect::<Vec<_>>();
                        (group, output_values)
                    };
                    let null = Value::Null;
                    let mut output_sets = vec![];
                    let mut state = outer_values.iter().collect::<Vec<_>>();
                    if aggregate.selects_inner {
                        output_sets.push(group);
                    } else {
                        // nasty hack - fill null values for inner so that the ixes work out right
                        for _ in aggregate.inner.mapping.iter() {
                            state.push(&null);
                        }
                    }
                    for output in output_values.iter() {
                        output_sets.push(output);
                    }
                    aggregate_step(aggregate, &output_sets[..], &mut state, &mut output.index);
                    group_start = group_end;
                }
                Some(output)
            }
        }
    }
}<|endoftext|>


<commit_before>use clap;
use crossbeam::sync::MsQueue;
use hyper::status::StatusCode;
use info::discovery_service_info;
use select::{select_collection, writable_environment};

use serde_json::to_string;
use std::{cmp, process, thread};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use walkdir::WalkDir;

use wdsapi::common::{ApiError, Credentials};
use wdsapi::document;

struct Context {
    creds: Credentials,
    env_id: String,
    col_id: String,
    retries: u32,
    pace: Duration,
    doc_id: AtomicUsize,
    tick: AtomicUsize,
    too_many_requests: AtomicUsize,
    other_errors: AtomicUsize,
    success: AtomicUsize,
    failure: AtomicUsize,
}

fn final_report(duration: Duration, context: &Context) -> () {
    println!("\nSent {} documents in {} seconds",
             context.success.load(Ordering::Relaxed),
             duration.as_secs());
    println!("Hit {} TooManyRequests (429) responses and {} unexpected errors",
             context.too_many_requests.load(Ordering::Relaxed),
             context.other_errors.load(Ordering::Relaxed));
    println!("{} documents failed",
             context.failure.load(Ordering::Relaxed));
}

fn send_file_with_retry(context: &Context, filename: &str) -> () {
    let mut unexplained_error_count = 0;
    let doc_id = format!("{:011x}",
                         context.doc_id
                                .fetch_add(1, Ordering::Relaxed));
    loop {
        match document::create(&context.creds,
                               &context.env_id,
                               &context.col_id,
                               None,
                               Some(&doc_id),
                               filename) {
            Ok(response) => {
                context.success.fetch_add(1, Ordering::Relaxed);
                println!("{} {}",
                         filename,
                         to_string(&response).unwrap_or_default());
                break;
            }
            Err(e) => {
                if let ApiError::Service(ref se) = e {
                    if se.status_code == StatusCode::TooManyRequests {
                        context.too_many_requests
                               .fetch_add(1, Ordering::Relaxed);
                        // The service says we're going too fast.
                        // Tell the main pace to wait four ticks,
                        // also double sleep here and resend.
                        context.tick.fetch_add(4, Ordering::Relaxed);
                        println!("{} sleep then retry after {}", filename, e);
                        thread::sleep(context.pace
                                             .checked_mul(2)
                                             .unwrap_or(context.pace));
                        continue;
                    }
                }
                context.other_errors.fetch_add(1, Ordering::Relaxed);
                unexplained_error_count += 1;
                if unexplained_error_count <= context.retries {
                    // We will retry, so tell the pace to wait another tick.
                    context.tick.fetch_add(1, Ordering::Relaxed);
                    println!("{} retry after fail to create document {}",
                             filename,
                             e);
                } else {
                    context.failure.fetch_add(1, Ordering::Relaxed);
                    println!("{} give up after fail to create document {}",
                             filename,
                             e);
                    break;
                }
            }
        }
    }
}

fn push_worker(context: &Context, queue: &MsQueue<String>) -> () {
    loop {
        let filename = queue.pop();
        if filename.is_empty() {
            break;
        };
        send_file_with_retry(context, &filename);
    }
}

pub fn add_document(creds: Credentials, matches: &clap::ArgMatches) {
    let info = discovery_service_info(creds);
    let env_info = writable_environment(&info);
    let collection = select_collection(&env_info, matches);
    let env_id = env_info.environment_id;
    let col_id = collection["collection_id"]
        .as_str()
        .expect("Internal error: missing collection_id");
    let retries: u32 = matches.value_of("retries")
                              .unwrap_or("2")
                              .parse()
                              .expect("Retries must be an integer");
    let threads: u32 = matches.value_of("threads")
                              .unwrap_or("64")
                              .parse()
                              .expect("Threads must be an integer");
    let pace: u64 = matches.value_of("pace")
                           .unwrap_or("500")
                           .parse()
                           .expect("Pace must be an integer");
    let pace = Duration::from_millis(pace);
    let doc_id: usize = match matches.value_of("document-id") {
        Some(id) => {
            usize::from_str_radix(id, 16)
                .expect("Document-id must be a hexadecimal integer")
        }
        None => {
            // Our default starting document id is
            // milliseconds elapsed since the epoch.
            let dur = SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .unwrap_or_else(|_| Duration::new(0, 0));
            1000 * dur.as_secs() as usize +
            (dur.subsec_nanos() as usize / 1000000)
        }
    };
    let context = Arc::new(Context {
        creds: info.creds.clone(),
        env_id: env_id.clone(),
        col_id: col_id.to_string(),
        retries: retries,
        doc_id: AtomicUsize::new(doc_id),
        pace: pace,
        tick: AtomicUsize::new(0),
        too_many_requests: AtomicUsize::new(0),
        other_errors: AtomicUsize::new(0),
        success: AtomicUsize::new(0),
        failure: AtomicUsize::new(0),
    });
    let queue = Arc::new(MsQueue::new());

    // Fire up a thread pool...
    for _ in 0..threads {
        let worker_item = context.clone();
        let worker_queue = queue.clone();
        thread::spawn(move || push_worker(&worker_item, &worker_queue));
    }

    let base_time = Instant::now();

    // Send work into the thread pool...
    for path in matches.values_of("paths").unwrap() {
        for entry in WalkDir::new(path)
            .sort_by(|a, b| a.cmp(b))
            .into_iter()
            .filter_map(|e| e.ok())
            .filter(|e| e.file_type().is_file()) {
            if let Some(filename) = entry.path().to_str() {
                let filename = filename.to_string();
                context.tick.fetch_add(1, Ordering::Relaxed);
                queue.push(filename);
                while let Some(sleep_duration) =
                    pace.checked_mul(context.tick
                                            .load(Ordering::Relaxed) as
                                     u32)
                        .expect("Ran too long?!")
                        .checked_sub(base_time.elapsed()) {
                    thread::sleep(sleep_duration);
                }
            }
        }
    }

    // Tell my threads to shutdown.
    for _ in 0..threads {
        queue.push(String::new());
    }

    let mut wait_count = 0;
    // Wait for the the threads to complete, but not forever.
    while let Some(item) = queue.try_pop() {
        wait_count += 1;
        queue.push(item);
        thread::sleep(Duration::from_secs(1));
        if wait_count > cmp::max(30, threads) {
            println!("Timeout waiting for worker thread shutdown. Aborting.");
            final_report(base_time.elapsed(), &context);
            process::exit(1);
        }
    }
    final_report(base_time.elapsed(), &context);
}
<commit_msg>Better thread handling in add-document, fixes #12<commit_after>use clap;
use crossbeam::sync::MsQueue;
use hyper::status::StatusCode;
use info::discovery_service_info;
use select::{select_collection, writable_environment};

use serde_json::to_string;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::thread::JoinHandle;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use walkdir::WalkDir;

use wdsapi::common::{ApiError, Credentials};
use wdsapi::document;

struct Context {
    creds: Credentials,
    env_id: String,
    col_id: String,
    retries: u32,
    pace: Duration,
    doc_id: AtomicUsize,
    tick: AtomicUsize,
    too_many_requests: AtomicUsize,
    other_errors: AtomicUsize,
    success: AtomicUsize,
    failure: AtomicUsize,
}

fn final_report(duration: Duration, context: &Context) -> () {
    println!("\nSent {} documents in {} seconds",
             context.success.load(Ordering::Relaxed),
             duration.as_secs());
    println!("Hit {} TooManyRequests (429) responses and {} unexpected errors",
             context.too_many_requests.load(Ordering::Relaxed),
             context.other_errors.load(Ordering::Relaxed));
    println!("{} documents failed",
             context.failure.load(Ordering::Relaxed));
}

fn send_file_with_retry(context: &Context, filename: &str) -> () {
    let mut unexplained_error_count = 0;
    let doc_id = format!("{:011x}",
                         context.doc_id
                                .fetch_add(1, Ordering::Relaxed));
    loop {
        match document::create(&context.creds,
                               &context.env_id,
                               &context.col_id,
                               None,
                               Some(&doc_id),
                               filename) {
            Ok(response) => {
                context.success.fetch_add(1, Ordering::Relaxed);
                println!("{} {}",
                         filename,
                         to_string(&response).unwrap_or_default());
                break;
            }
            Err(e) => {
                if let ApiError::Service(ref se) = e {
                    if se.status_code == StatusCode::TooManyRequests {
                        context.too_many_requests
                               .fetch_add(1, Ordering::Relaxed);
                        // The service says we're going too fast.
                        // Tell the main pace to wait four ticks,
                        // also double sleep here and resend.
                        context.tick.fetch_add(4, Ordering::Relaxed);
                        println!("{} sleep then retry after {}", filename, e);
                        thread::sleep(context.pace
                                             .checked_mul(2)
                                             .unwrap_or(context.pace));
                        continue;
                    }
                }
                context.other_errors.fetch_add(1, Ordering::Relaxed);
                unexplained_error_count += 1;
                if unexplained_error_count <= context.retries {
                    // We will retry, so tell the pace to wait another tick.
                    context.tick.fetch_add(1, Ordering::Relaxed);
                    println!("{} retry after fail to create document {}",
                             filename,
                             e);
                } else {
                    context.failure.fetch_add(1, Ordering::Relaxed);
                    println!("{} give up after fail to create document {}",
                             filename,
                             e);
                    break;
                }
            }
        }
    }
}

fn push_worker(context: &Context, queue: &MsQueue<String>) -> () {
    loop {
        let filename = queue.pop();
        if filename.is_empty() {
            break;
        };
        send_file_with_retry(context, &filename);
    }
}

pub fn add_document(creds: Credentials, matches: &clap::ArgMatches) {
    let info = discovery_service_info(creds);
    let env_info = writable_environment(&info);
    let collection = select_collection(&env_info, matches);
    let env_id = env_info.environment_id;
    let col_id = collection["collection_id"]
        .as_str()
        .expect("Internal error: missing collection_id");
    let retries: u32 = matches.value_of("retries")
                              .unwrap_or("2")
                              .parse()
                              .expect("Retries must be an integer");
    let thread_count: u32 = matches.value_of("threads")
                                   .unwrap_or("64")
                                   .parse()
                                   .expect("Threads must be an integer");
    let pace: u64 = matches.value_of("pace")
                           .unwrap_or("500")
                           .parse()
                           .expect("Pace must be an integer");
    let pace = Duration::from_millis(pace);
    let doc_id: usize = match matches.value_of("document-id") {
        Some(id) => {
            usize::from_str_radix(id, 16)
                .expect("Document-id must be a hexadecimal integer")
        }
        None => {
            // Our default starting document id is
            // milliseconds elapsed since the epoch.
            let dur = SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .unwrap_or_else(|_| Duration::new(0, 0));
            1000 * dur.as_secs() as usize +
            (dur.subsec_nanos() as usize / 1000000)
        }
    };
    let context = Arc::new(Context {
        creds: info.creds.clone(),
        env_id: env_id.clone(),
        col_id: col_id.to_string(),
        retries: retries,
        doc_id: AtomicUsize::new(doc_id),
        pace: pace,
        tick: AtomicUsize::new(0),
        too_many_requests: AtomicUsize::new(0),
        other_errors: AtomicUsize::new(0),
        success: AtomicUsize::new(0),
        failure: AtomicUsize::new(0),
    });
    let queue = Arc::new(MsQueue::new());

    // Fire up a thread pool...
    let threads: Vec<JoinHandle<_>> = (0..thread_count)
        .map(|_| {
            let worker_item = context.clone();
            let worker_queue = queue.clone();
            thread::spawn(move || push_worker(&worker_item, &worker_queue))
        })
        .collect();

    let base_time = Instant::now();

    // Send work into the thread pool...
    for path in matches.values_of("paths").unwrap() {
        for entry in WalkDir::new(path)
            .sort_by(|a, b| a.cmp(b))
            .into_iter()
            .filter_map(|e| e.ok())
            .filter(|e| e.file_type().is_file()) {
            if let Some(filename) = entry.path().to_str() {
                let filename = filename.to_string();
                context.tick.fetch_add(1, Ordering::Relaxed);
                queue.push(filename);
                while let Some(sleep_duration) =
                    pace.checked_mul(context.tick
                                            .load(Ordering::Relaxed) as
                                     u32)
                        .expect("Ran too long?!")
                        .checked_sub(base_time.elapsed()) {
                    thread::sleep(sleep_duration);
                }
            }
        }
    }

    // Tell my threads to shutdown.
    for _ in 0..thread_count {
        queue.push(String::new());
    }
    for thread in threads {
        thread.join().expect("Failed to join thread?!");
    }
    final_report(base_time.elapsed(), &context);
}
<|endoftext|>


<commit_before>extern crate errno;

extern crate libc;

use super::constants::*;
use super::ffi::*;

use std::ffi::CString;
use std::os::unix::raw::{gid_t, uid_t};
use std::ptr;
use std::result;
use std::str;

pub type Error = errno::Errno;
pub type Result<T> = result::Result<T, Error>;

fn check_call<T>(res: libc::c_long, value: T) -> Result<T> {
    if res == -1 {
        Err(errno::errno())
    } else {
        Ok(value)
    }
}

fn get_keyring(id: KeyringSerial, create: bool) -> Result<Keyring> {
    let res = unsafe { keyctl_get_keyring_ID(id, create as libc::c_int) };
    check_call(res as libc::c_long, Keyring { id: res, })
}

pub struct Keyring {
    id: KeyringSerial,
}

impl Keyring {
    pub fn set_default(keyring: DefaultKeyring) -> Result<()> {
        check_call(unsafe { keyctl_set_reqkey_keyring(keyring.serial()) }, ())
    }

    pub fn export_session_keyring_to_parent() -> Result<()> {
        check_call(unsafe { keyctl_session_to_parent() }, ())
    }

    pub fn attach(id: KeyringSerial) -> Result<Self> {
        get_keyring(id, false)
    }

    pub fn attach_or_create(id: KeyringSerial) -> Result<Self> {
        get_keyring(id, true)
    }

    pub fn join_anonymous_session() -> Result<Self> {
        let res = unsafe { keyctl_join_session_keyring(ptr::null()) };
        check_call(res as libc::c_long, Keyring { id: res })
    }

    pub fn join_session(name: &str) -> Result<Self> {
        let nameptr = CString::new(name).unwrap().as_ptr();
        let res = unsafe { keyctl_join_session_keyring(nameptr) };
        check_call(res as libc::c_long, Keyring { id: res })
    }

    pub fn clear(&mut self) -> Result<()> {
        check_call(unsafe { keyctl_clear(self.id) }, ())
    }

    pub fn link(&mut self, key: &Key) -> Result<()> {
        check_call(unsafe { keyctl_link(key.id, self.id) }, ())
    }

    pub fn unlink(&mut self, key: &Key) -> Result<()> {
        check_call(unsafe { keyctl_unlink(key.id, self.id) }, ())
    }

    pub fn search(&self, type_: &str, description: &str, dest: Option<Keyring>) -> Result<Key> {
        let typeptr = CString::new(type_).unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let destid = if let Some(dest_ring) = dest {
                dest_ring.id
            } else {
                0
            };
        let res = unsafe { keyctl_search(self.id, typeptr, descptr, destid) };
        check_call(res, Key { id: res as key_serial_t, })
    }

    pub fn read(&self) -> Result<Vec<Key>> {
        unimplemented!()
    }

    pub fn attach_persistent(&mut self) -> Result<Keyring> {
        let res = unsafe { keyctl_get_persistent(-1, self.id) };
        check_call(res, Keyring { id: res as key_serial_t, })
    }

    pub fn add_key(&mut self, description: &str, payload: &[u8]) -> Result<Key> {
        let typeptr = CString::new("user").unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let res = unsafe { add_key(typeptr, descptr, payload.as_ptr() as *const libc::c_void, payload.len(), self.id) };
        check_call(res as libc::c_long, Key { id: res, })
    }

    pub fn add_keyring(&mut self) -> Result<Keyring> {
        let typeptr = CString::new("keyring").unwrap().as_ptr();
        let res = unsafe { add_key(typeptr, ptr::null(), ptr::null(), 0, self.id) };
        check_call(res as libc::c_long, Keyring { id: res, })
    }

    pub fn request_key(&mut self) -> Result<Key> {
        unimplemented!()
    }
}

pub struct Key {
    id: KeyringSerial,
}

impl Key {
    pub fn keyring(&self) -> Result<Keyring> {
        get_keyring(self.id, false)
    }

    pub fn update(&mut self, data: &[u8]) -> Result<()> {
        check_call(unsafe { keyctl_update(self.id, data.as_ptr() as *const libc::c_void, data.len()) }, ())
    }

    pub fn revoke(self) -> Result<()> {
        check_call(unsafe { keyctl_revoke(self.id) }, ())
    }

    pub fn chown(&mut self, uid: uid_t, gid: gid_t) -> Result<()> {
        check_call(unsafe { keyctl_chown(self.id, uid, gid) }, ())
    }

    pub fn set_permissions(&mut self, perms: KeyPermissions) -> Result<()> {
        check_call(unsafe { keyctl_setperm(self.id, perms) }, ())
    }

    pub fn description(&self) -> Result<String> {
        let sz = unsafe { keyctl_describe(self.id, ptr::null_mut(), 0) };
        if sz < 0 {
            return Err(errno::errno());
        }
        let mut buffer = Vec::with_capacity(sz as usize);
        let res = unsafe { keyctl_describe(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) };
        if res < 0 {
            return Err(errno::errno());
        }
        let str_slice = str::from_utf8(&buffer[..]).unwrap();
        Ok(str_slice.to_owned())
    }

    pub fn read(&self) -> Result<Vec<u8>> {
        let sz = unsafe { keyctl_read(self.id, ptr::null_mut(), 0) };
        if sz < 0 {
            return Err(errno::errno());
        }
        let mut buffer = Vec::with_capacity(sz as usize);
        let res = unsafe { keyctl_read(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) };
        if res < 0 {
            return Err(errno::errno());
        }
        Ok(buffer)
    }

    pub fn set_timeout(&mut self, timeout: u32) -> Result<()> {
        check_call(unsafe { keyctl_set_timeout(self.id, timeout) }, ())
    }

    pub fn get_security(&self) -> Result<String> {
        let sz = unsafe { keyctl_get_security(self.id, ptr::null_mut(), 0) };
        if sz < 0 {
            return Err(errno::errno());
        }
        let mut buffer = Vec::with_capacity(sz as usize);
        let res = unsafe { keyctl_get_security(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) };
        if res < 0 {
            return Err(errno::errno());
        }
        let str_slice = str::from_utf8(&buffer[..]).unwrap();
        Ok(str_slice.to_owned())
    }

    pub fn invalidate(self) -> Result<()> {
        check_call(unsafe { keyctl_invalidate(self.id) }, ())
    }
}
<commit_msg>api: search attaches to the current keyring<commit_after>extern crate errno;

extern crate libc;

use super::constants::*;
use super::ffi::*;

use std::ffi::CString;
use std::os::unix::raw::{gid_t, uid_t};
use std::ptr;
use std::result;
use std::str;

pub type Error = errno::Errno;
pub type Result<T> = result::Result<T, Error>;

fn check_call<T>(res: libc::c_long, value: T) -> Result<T> {
    if res == -1 {
        Err(errno::errno())
    } else {
        Ok(value)
    }
}

fn get_keyring(id: KeyringSerial, create: bool) -> Result<Keyring> {
    let res = unsafe { keyctl_get_keyring_ID(id, create as libc::c_int) };
    check_call(res as libc::c_long, Keyring { id: res, })
}

pub struct Keyring {
    id: KeyringSerial,
}

impl Keyring {
    pub fn set_default(keyring: DefaultKeyring) -> Result<()> {
        check_call(unsafe { keyctl_set_reqkey_keyring(keyring.serial()) }, ())
    }

    pub fn export_session_keyring_to_parent() -> Result<()> {
        check_call(unsafe { keyctl_session_to_parent() }, ())
    }

    pub fn attach(id: KeyringSerial) -> Result<Self> {
        get_keyring(id, false)
    }

    pub fn attach_or_create(id: KeyringSerial) -> Result<Self> {
        get_keyring(id, true)
    }

    pub fn join_anonymous_session() -> Result<Self> {
        let res = unsafe { keyctl_join_session_keyring(ptr::null()) };
        check_call(res as libc::c_long, Keyring { id: res })
    }

    pub fn join_session(name: &str) -> Result<Self> {
        let nameptr = CString::new(name).unwrap().as_ptr();
        let res = unsafe { keyctl_join_session_keyring(nameptr) };
        check_call(res as libc::c_long, Keyring { id: res })
    }

    pub fn clear(&mut self) -> Result<()> {
        check_call(unsafe { keyctl_clear(self.id) }, ())
    }

    pub fn link(&mut self, key: &Key) -> Result<()> {
        check_call(unsafe { keyctl_link(key.id, self.id) }, ())
    }

    pub fn unlink(&mut self, key: &Key) -> Result<()> {
        check_call(unsafe { keyctl_unlink(key.id, self.id) }, ())
    }

    pub fn search(&mut self, type_: &str, description: &str) -> Result<Key> {
        let typeptr = CString::new(type_).unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let res = unsafe { keyctl_search(self.id, typeptr, descptr, self.id) };
        check_call(res, Key { id: res as key_serial_t, })
    }

    pub fn read(&self) -> Result<Vec<Key>> {
        unimplemented!()
    }

    pub fn attach_persistent(&mut self) -> Result<Keyring> {
        let res = unsafe { keyctl_get_persistent(-1, self.id) };
        check_call(res, Keyring { id: res as key_serial_t, })
    }

    pub fn add_key(&mut self, description: &str, payload: &[u8]) -> Result<Key> {
        let typeptr = CString::new("user").unwrap().as_ptr();
        let descptr = CString::new(description).unwrap().as_ptr();
        let res = unsafe { add_key(typeptr, descptr, payload.as_ptr() as *const libc::c_void, payload.len(), self.id) };
        check_call(res as libc::c_long, Key { id: res, })
    }

    pub fn add_keyring(&mut self) -> Result<Keyring> {
        let typeptr = CString::new("keyring").unwrap().as_ptr();
        let res = unsafe { add_key(typeptr, ptr::null(), ptr::null(), 0, self.id) };
        check_call(res as libc::c_long, Keyring { id: res, })
    }

    pub fn request_key(&mut self) -> Result<Key> {
        unimplemented!()
    }
}

pub struct Key {
    id: KeyringSerial,
}

impl Key {
    pub fn keyring(&self) -> Result<Keyring> {
        get_keyring(self.id, false)
    }

    pub fn update(&mut self, data: &[u8]) -> Result<()> {
        check_call(unsafe { keyctl_update(self.id, data.as_ptr() as *const libc::c_void, data.len()) }, ())
    }

    pub fn revoke(self) -> Result<()> {
        check_call(unsafe { keyctl_revoke(self.id) }, ())
    }

    pub fn chown(&mut self, uid: uid_t, gid: gid_t) -> Result<()> {
        check_call(unsafe { keyctl_chown(self.id, uid, gid) }, ())
    }

    pub fn set_permissions(&mut self, perms: KeyPermissions) -> Result<()> {
        check_call(unsafe { keyctl_setperm(self.id, perms) }, ())
    }

    pub fn description(&self) -> Result<String> {
        let sz = unsafe { keyctl_describe(self.id, ptr::null_mut(), 0) };
        if sz < 0 {
            return Err(errno::errno());
        }
        let mut buffer = Vec::with_capacity(sz as usize);
        let res = unsafe { keyctl_describe(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) };
        if res < 0 {
            return Err(errno::errno());
        }
        let str_slice = str::from_utf8(&buffer[..]).unwrap();
        Ok(str_slice.to_owned())
    }

    pub fn read(&self) -> Result<Vec<u8>> {
        let sz = unsafe { keyctl_read(self.id, ptr::null_mut(), 0) };
        if sz < 0 {
            return Err(errno::errno());
        }
        let mut buffer = Vec::with_capacity(sz as usize);
        let res = unsafe { keyctl_read(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) };
        if res < 0 {
            return Err(errno::errno());
        }
        Ok(buffer)
    }

    pub fn set_timeout(&mut self, timeout: u32) -> Result<()> {
        check_call(unsafe { keyctl_set_timeout(self.id, timeout) }, ())
    }

    pub fn get_security(&self) -> Result<String> {
        let sz = unsafe { keyctl_get_security(self.id, ptr::null_mut(), 0) };
        if sz < 0 {
            return Err(errno::errno());
        }
        let mut buffer = Vec::with_capacity(sz as usize);
        let res = unsafe { keyctl_get_security(self.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) };
        if res < 0 {
            return Err(errno::errno());
        }
        let str_slice = str::from_utf8(&buffer[..]).unwrap();
        Ok(str_slice.to_owned())
    }

    pub fn invalidate(self) -> Result<()> {
        check_call(unsafe { keyctl_invalidate(self.id) }, ())
    }
}
<|endoftext|>


<commit_before>use enums::{AlphaMode, FeatureLevel, PresentOptions, RenderTargetType, RenderTargetUsage};
use error::D2DResult;
use factory::Factory;
use math;
use render_target::RenderTarget;

use std::ptr;

use direct3d11::flags::Format;
use winapi::shared::windef::HWND;
use winapi::shared::winerror::SUCCEEDED;
use winapi::um::d2d1::{D2D1_HWND_RENDER_TARGET_PROPERTIES, D2D1_RENDER_TARGET_PROPERTIES,
                       D2D1_SIZE_U, ID2D1HwndRenderTarget, ID2D1RenderTarget};
use winapi::um::dcommon::D2D1_PIXEL_FORMAT;
use wio::com::ComPtr;

#[derive(Clone)]
pub struct HwndRenderTarget {
    ptr: ComPtr<ID2D1HwndRenderTarget>,
}

impl HwndRenderTarget {
    pub fn create<'a>(factory: &'a Factory) -> HwndRenderTargetBuilder<'a> {
        HwndRenderTargetBuilder::new(factory)
    }

    pub fn resize(&self, pixel_size: math::SizeU) -> D2DResult<()> {
        unsafe {
            let hr = self.ptr.Resize(&pixel_size.0);
            if SUCCEEDED(hr) {
                Ok(())
            } else {
                Err(hr.into())
            }
        }
    }

    pub unsafe fn from_raw(raw: *mut ID2D1HwndRenderTarget) -> Self {
        HwndRenderTarget {
            ptr: ComPtr::from_raw(raw),
        }
    }

    pub unsafe fn get_raw(&self) -> *mut ID2D1HwndRenderTarget {
        self.ptr.as_raw()
    }
}

impl RenderTarget for HwndRenderTarget {
    unsafe fn rt<'a>(&self) -> &'a mut ID2D1RenderTarget {
        &mut *(self.ptr.as_raw() as *mut _)
    }
}

unsafe impl Send for HwndRenderTarget {}
unsafe impl Sync for HwndRenderTarget {}

pub struct HwndRenderTargetBuilder<'a> {
    factory: &'a Factory,
    rt_props: D2D1_RENDER_TARGET_PROPERTIES,
    hwnd_props: D2D1_HWND_RENDER_TARGET_PROPERTIES,
}

const DEFAULT_PROPS: D2D1_RENDER_TARGET_PROPERTIES = D2D1_RENDER_TARGET_PROPERTIES {
    _type: RenderTargetType::Hardware as u32,
    pixelFormat: D2D1_PIXEL_FORMAT {
        format: Format::B8G8R8A8Unorm as u32,
        alphaMode: AlphaMode::Premultiplied as u32,
    },
    dpiX: 0.0,
    dpiY: 0.0,
    usage: 0,
    minLevel: 0,
};

const DEFAULT_HWND_PROPS: D2D1_HWND_RENDER_TARGET_PROPERTIES = D2D1_HWND_RENDER_TARGET_PROPERTIES {
    hwnd: ptr::null_mut(),
    pixelSize: D2D1_SIZE_U {
        width: 0,
        height: 0,
    },
    presentOptions: 0,
};

impl<'a> HwndRenderTargetBuilder<'a> {
    pub fn new(factory: &'a Factory) -> Self {
        HwndRenderTargetBuilder {
            factory,
            rt_props: DEFAULT_PROPS,
            hwnd_props: DEFAULT_HWND_PROPS,
        }
    }

    pub fn build(self) -> D2DResult<HwndRenderTarget> {
        unsafe {
            let mut ptr = ptr::null_mut();
            let hr = (*self.factory.get_raw()).CreateHwndRenderTarget(
                &self.rt_props,
                &self.hwnd_props,
                &mut ptr,
            );

            if SUCCEEDED(hr) {
                Ok(HwndRenderTarget::from_raw(ptr))
            } else {
                Err(hr.into())
            }
        }
    }

    pub fn with_target_type(mut self, target_type: RenderTargetType) -> Self {
        self.rt_props._type = target_type as u32;
        self
    }

    pub fn with_format(mut self, format: Format) -> Self {
        self.rt_props.pixelFormat.format = format as u32;
        self
    }

    pub fn with_alpha_mode(mut self, alpha_mode: AlphaMode) -> Self {
        self.rt_props.pixelFormat.alphaMode = alpha_mode as u32;
        self
    }

    pub fn with_dpi(mut self, dpi_x: f32, dpi_y: f32) -> Self {
        self.rt_props.dpiX = dpi_x;
        self.rt_props.dpiY = dpi_y;
        self
    }

    pub fn with_usage(mut self, usage: RenderTargetUsage) -> Self {
        self.rt_props.usage = usage.0;
        self
    }

    pub fn with_feature_level(mut self, level: FeatureLevel) -> Self {
        self.rt_props.minLevel = level as u32;
        self
    }

    pub fn with_hwnd(mut self, hwnd: HWND) -> Self {
        self.hwnd_props.hwnd = hwnd;
        self
    }

    pub fn with_pixel_size(mut self, size: math::SizeU) -> Self {
        self.hwnd_props.pixelSize = size.0;
        self
    }

    pub fn with_present_options(mut self, options: PresentOptions) -> Self {
        self.hwnd_props.presentOptions = options.0;
        self
    }
}
<commit_msg>get_hwnd<commit_after>use enums::{AlphaMode, FeatureLevel, PresentOptions, RenderTargetType, RenderTargetUsage};
use error::D2DResult;
use factory::Factory;
use math;
use render_target::RenderTarget;

use std::ptr;

use direct3d11::flags::Format;
use winapi::shared::windef::HWND;
use winapi::shared::winerror::SUCCEEDED;
use winapi::um::d2d1::{D2D1_HWND_RENDER_TARGET_PROPERTIES, D2D1_RENDER_TARGET_PROPERTIES,
                       D2D1_SIZE_U, ID2D1HwndRenderTarget, ID2D1RenderTarget};
use winapi::um::dcommon::D2D1_PIXEL_FORMAT;
use wio::com::ComPtr;

#[derive(Clone)]
pub struct HwndRenderTarget {
    ptr: ComPtr<ID2D1HwndRenderTarget>,
}

impl HwndRenderTarget {
    pub fn create<'a>(factory: &'a Factory) -> HwndRenderTargetBuilder<'a> {
        HwndRenderTargetBuilder::new(factory)
    }

    pub fn resize(&self, pixel_size: math::SizeU) -> D2DResult<()> {
        unsafe {
            let hr = self.ptr.Resize(&pixel_size.0);
            if SUCCEEDED(hr) {
                Ok(())
            } else {
                Err(hr.into())
            }
        }
    }

    pub fn get_hwnd(&self) -> HWND {
        unsafe { self.ptr.GetHwnd() }
    }

    pub unsafe fn from_raw(raw: *mut ID2D1HwndRenderTarget) -> Self {
        HwndRenderTarget {
            ptr: ComPtr::from_raw(raw),
        }
    }

    pub unsafe fn get_raw(&self) -> *mut ID2D1HwndRenderTarget {
        self.ptr.as_raw()
    }
}

impl RenderTarget for HwndRenderTarget {
    unsafe fn rt<'a>(&self) -> &'a mut ID2D1RenderTarget {
        &mut *(self.ptr.as_raw() as *mut _)
    }
}

unsafe impl Send for HwndRenderTarget {}
unsafe impl Sync for HwndRenderTarget {}

pub struct HwndRenderTargetBuilder<'a> {
    factory: &'a Factory,
    rt_props: D2D1_RENDER_TARGET_PROPERTIES,
    hwnd_props: D2D1_HWND_RENDER_TARGET_PROPERTIES,
}

const DEFAULT_PROPS: D2D1_RENDER_TARGET_PROPERTIES = D2D1_RENDER_TARGET_PROPERTIES {
    _type: RenderTargetType::Hardware as u32,
    pixelFormat: D2D1_PIXEL_FORMAT {
        format: Format::B8G8R8A8Unorm as u32,
        alphaMode: AlphaMode::Premultiplied as u32,
    },
    dpiX: 0.0,
    dpiY: 0.0,
    usage: 0,
    minLevel: 0,
};

const DEFAULT_HWND_PROPS: D2D1_HWND_RENDER_TARGET_PROPERTIES = D2D1_HWND_RENDER_TARGET_PROPERTIES {
    hwnd: ptr::null_mut(),
    pixelSize: D2D1_SIZE_U {
        width: 0,
        height: 0,
    },
    presentOptions: 0,
};

impl<'a> HwndRenderTargetBuilder<'a> {
    pub fn new(factory: &'a Factory) -> Self {
        HwndRenderTargetBuilder {
            factory,
            rt_props: DEFAULT_PROPS,
            hwnd_props: DEFAULT_HWND_PROPS,
        }
    }

    pub fn build(self) -> D2DResult<HwndRenderTarget> {
        unsafe {
            let mut ptr = ptr::null_mut();
            let hr = (*self.factory.get_raw()).CreateHwndRenderTarget(
                &self.rt_props,
                &self.hwnd_props,
                &mut ptr,
            );

            if SUCCEEDED(hr) {
                Ok(HwndRenderTarget::from_raw(ptr))
            } else {
                Err(hr.into())
            }
        }
    }

    pub fn with_target_type(mut self, target_type: RenderTargetType) -> Self {
        self.rt_props._type = target_type as u32;
        self
    }

    pub fn with_format(mut self, format: Format) -> Self {
        self.rt_props.pixelFormat.format = format as u32;
        self
    }

    pub fn with_alpha_mode(mut self, alpha_mode: AlphaMode) -> Self {
        self.rt_props.pixelFormat.alphaMode = alpha_mode as u32;
        self
    }

    pub fn with_dpi(mut self, dpi_x: f32, dpi_y: f32) -> Self {
        self.rt_props.dpiX = dpi_x;
        self.rt_props.dpiY = dpi_y;
        self
    }

    pub fn with_usage(mut self, usage: RenderTargetUsage) -> Self {
        self.rt_props.usage = usage.0;
        self
    }

    pub fn with_feature_level(mut self, level: FeatureLevel) -> Self {
        self.rt_props.minLevel = level as u32;
        self
    }

    pub fn with_hwnd(mut self, hwnd: HWND) -> Self {
        self.hwnd_props.hwnd = hwnd;
        self
    }

    pub fn with_pixel_size(mut self, size: math::SizeU) -> Self {
        self.hwnd_props.pixelSize = size.0;
        self
    }

    pub fn with_present_options(mut self, options: PresentOptions) -> Self {
        self.hwnd_props.presentOptions = options.0;
        self
    }
}
<|endoftext|>


<commit_before>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers
// contributed by TeXitoi

//extern crate libc;
// exporting needed things from libc for linux x64 (still unstable)
#[cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "x86")))]
mod libc {
    #![allow(non_camel_case_types)]
    #[repr(u8)]
    pub enum c_void { __variant1, __variant2 }
    pub type c_int = i32;
    #[cfg(target_arch = "x86_64")] pub type size_t = u64;
    #[cfg(target_arch = "x86")] pub type size_t = u32;
    extern { pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; }
}

use std::io::{Read, Write};
use std::ptr::copy;
use std::thread;

struct Tables {
    table8: [u8;1 << 8],
    table16: [u16;1 << 16]
}

impl Tables {
    fn new() -> Tables {
        let mut table8 = [0;1 << 8];
        for (i, v) in table8.iter_mut().enumerate() {
            *v = Tables::computed_cpl8(i as u8);
        }
        let mut table16 = [0;1 << 16];
        for (i, v) in table16.iter_mut().enumerate() {
            *v = (table8[i & 255] as u16) << 8 |
                 table8[i >> 8]  as u16;
        }
        Tables { table8: table8, table16: table16 }
    }

    fn computed_cpl8(c: u8) -> u8 {
        match c {
            b'A' | b'a' => b'T',
            b'C' | b'c' => b'G',
            b'G' | b'g' => b'C',
            b'T' | b't' => b'A',
            b'U' | b'u' => b'A',
            b'M' | b'm' => b'K',
            b'R' | b'r' => b'Y',
            b'W' | b'w' => b'W',
            b'S' | b's' => b'S',
            b'Y' | b'y' => b'R',
            b'K' | b'k' => b'M',
            b'V' | b'v' => b'B',
            b'H' | b'h' => b'D',
            b'D' | b'd' => b'H',
            b'B' | b'b' => b'V',
            b'N' | b'n' => b'N',
            i => i,
        }
    }

    /// Retrieves the complement for `i`.
    fn cpl8(&self, i: u8) -> u8 {
        self.table8[i as usize]
    }

    /// Retrieves the complement for `i`.
    fn cpl16(&self, i: u16) -> u16 {
        self.table16[i as usize]
    }
}

/// Finds the first position at which `b` occurs in `s`.
fn memchr(h: &[u8], n: u8) -> Option<usize> {
    use libc::{c_void, c_int, size_t};
    let res = unsafe {
        libc::memchr(h.as_ptr() as *const c_void, n as c_int, h.len() as size_t)
    };
    if res.is_null() {
        None
    } else {
        Some(res as usize - h.as_ptr() as usize)
    }
}

/// A mutable iterator over DNA sequences
struct MutDnaSeqs<'a> { s: &'a mut [u8] }
fn mut_dna_seqs<'a>(s: &'a mut [u8]) -> MutDnaSeqs<'a> {
    MutDnaSeqs { s: s }
}
impl<'a> Iterator for MutDnaSeqs<'a> {
    type Item = &'a mut [u8];

    fn next(&mut self) -> Option<&'a mut [u8]> {
        let tmp = std::mem::replace(&mut self.s, &mut []);
        let tmp = match memchr(tmp, b'\n') {
            Some(i) => &mut tmp[i + 1 ..],
            None => return None,
        };
        let (seq, tmp) = match memchr(tmp, b'>') {
            Some(i) => tmp.split_at_mut(i),
            None => {
                let len = tmp.len();
                tmp.split_at_mut(len)
            }
        };
        self.s = tmp;
        Some(seq)
    }
}

/// Length of a normal line without the terminating \n.
const LINE_LEN: usize = 60;

/// Compute the reverse complement.
fn reverse_complement(seq: &mut [u8], tables: &Tables) {
    let len = seq.len() - 1;
    let seq = &mut seq[..len];// Drop the last newline
    let off = LINE_LEN - len % (LINE_LEN + 1);
    let mut i = LINE_LEN;
    while i < len {
        unsafe {
            copy(seq.as_ptr().offset((i - off) as isize),
                 seq.as_mut_ptr().offset((i - off + 1) as isize), off);
            *seq.get_unchecked_mut(i - off) = b'\n';
        }
        i += LINE_LEN + 1;
    }

    let div = len / 4;
    let rem = len % 4;
    unsafe {
        let mut left = seq.as_mut_ptr() as *mut u16;
        // This is slow if len % 2 != 0 but still faster than bytewise operations.
        let mut right = seq.as_mut_ptr().offset(len as isize - 2) as *mut u16;
        let end = left.offset(div as isize);
        while left != end {
            let tmp = tables.cpl16(*left);
            *left = tables.cpl16(*right);
            *right = tmp;
            left = left.offset(1);
            right = right.offset(-1);
        }

        let end = end as *mut u8;
        match rem {
            1 => *end = tables.cpl8(*end),
            2 => {
                let tmp = tables.cpl8(*end);
                *end = tables.cpl8(*end.offset(1));
                *end.offset(1) = tmp;
            },
            3 => {
                *end.offset(1) = tables.cpl8(*end.offset(1));
                let tmp = tables.cpl8(*end);
                *end = tables.cpl8(*end.offset(2));
                *end.offset(2) = tmp;
            },
            _ => { },
        }
    }
}

/// Executes a closure in parallel over the given iterator over mutable slice.
/// The closure `f` is run in parallel with an element of `iter`.
fn parallel<'a, I: Iterator, F>(iter: I, ref f: F)
        where I::Item: Send + 'a,
              F: Fn(I::Item) + Sync + 'a {
    iter.map(|x| {
        thread::scoped(move|| {
            f(x)
        })
    }).collect::<Vec<_>>();
}

fn main() {
    let stdin = std::io::stdin();
    let mut data = Vec::with_capacity(1024 * 1024);
    stdin.lock().read_to_end(&mut data).unwrap();
    let tables = &Tables::new();
    parallel(mut_dna_seqs(&mut data), |seq| reverse_complement(seq, tables));
    let stdout = std::io::stdout();
    stdout.lock().write_all(&data).unwrap();
}
<commit_msg>fix reverse_complement by reverting the pre thread::scoped fn parallel<commit_after>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers
// contributed by TeXitoi

//extern crate libc;
// exporting needed things from libc for linux x64 (still unstable)
#[cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "x86")))]
mod libc {
    #![allow(non_camel_case_types)]
    #[repr(u8)]
    pub enum c_void { __variant1, __variant2 }
    pub type c_int = i32;
    #[cfg(target_arch = "x86_64")] pub type size_t = u64;
    #[cfg(target_arch = "x86")] pub type size_t = u32;
    extern { pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; }
}

use std::io::{Read, Write};
use std::ptr::copy;
use std::thread;

struct Tables {
    table8: [u8;1 << 8],
    table16: [u16;1 << 16]
}

impl Tables {
    fn new() -> Tables {
        let mut table8 = [0;1 << 8];
        for (i, v) in table8.iter_mut().enumerate() {
            *v = Tables::computed_cpl8(i as u8);
        }
        let mut table16 = [0;1 << 16];
        for (i, v) in table16.iter_mut().enumerate() {
            *v = (table8[i & 255] as u16) << 8 |
                 table8[i >> 8]  as u16;
        }
        Tables { table8: table8, table16: table16 }
    }

    fn computed_cpl8(c: u8) -> u8 {
        match c {
            b'A' | b'a' => b'T',
            b'C' | b'c' => b'G',
            b'G' | b'g' => b'C',
            b'T' | b't' => b'A',
            b'U' | b'u' => b'A',
            b'M' | b'm' => b'K',
            b'R' | b'r' => b'Y',
            b'W' | b'w' => b'W',
            b'S' | b's' => b'S',
            b'Y' | b'y' => b'R',
            b'K' | b'k' => b'M',
            b'V' | b'v' => b'B',
            b'H' | b'h' => b'D',
            b'D' | b'd' => b'H',
            b'B' | b'b' => b'V',
            b'N' | b'n' => b'N',
            i => i,
        }
    }

    /// Retrieves the complement for `i`.
    fn cpl8(&self, i: u8) -> u8 {
        self.table8[i as usize]
    }

    /// Retrieves the complement for `i`.
    fn cpl16(&self, i: u16) -> u16 {
        self.table16[i as usize]
    }
}

/// Finds the first position at which `b` occurs in `s`.
fn memchr(h: &[u8], n: u8) -> Option<usize> {
    use libc::{c_void, c_int, size_t};
    let res = unsafe {
        libc::memchr(h.as_ptr() as *const c_void, n as c_int, h.len() as size_t)
    };
    if res.is_null() {
        None
    } else {
        Some(res as usize - h.as_ptr() as usize)
    }
}

/// A mutable iterator over DNA sequences
struct MutDnaSeqs<'a> { s: &'a mut [u8] }
fn mut_dna_seqs<'a>(s: &'a mut [u8]) -> MutDnaSeqs<'a> {
    MutDnaSeqs { s: s }
}
impl<'a> Iterator for MutDnaSeqs<'a> {
    type Item = &'a mut [u8];

    fn next(&mut self) -> Option<&'a mut [u8]> {
        let tmp = std::mem::replace(&mut self.s, &mut []);
        let tmp = match memchr(tmp, b'\n') {
            Some(i) => &mut tmp[i + 1 ..],
            None => return None,
        };
        let (seq, tmp) = match memchr(tmp, b'>') {
            Some(i) => tmp.split_at_mut(i),
            None => {
                let len = tmp.len();
                tmp.split_at_mut(len)
            }
        };
        self.s = tmp;
        Some(seq)
    }
}

/// Length of a normal line without the terminating \n.
const LINE_LEN: usize = 60;

/// Compute the reverse complement.
fn reverse_complement(seq: &mut [u8], tables: &Tables) {
    let len = seq.len() - 1;
    let seq = &mut seq[..len];// Drop the last newline
    let off = LINE_LEN - len % (LINE_LEN + 1);
    let mut i = LINE_LEN;
    while i < len {
        unsafe {
            copy(seq.as_ptr().offset((i - off) as isize),
                 seq.as_mut_ptr().offset((i - off + 1) as isize), off);
            *seq.get_unchecked_mut(i - off) = b'\n';
        }
        i += LINE_LEN + 1;
    }

    let div = len / 4;
    let rem = len % 4;
    unsafe {
        let mut left = seq.as_mut_ptr() as *mut u16;
        // This is slow if len % 2 != 0 but still faster than bytewise operations.
        let mut right = seq.as_mut_ptr().offset(len as isize - 2) as *mut u16;
        let end = left.offset(div as isize);
        while left != end {
            let tmp = tables.cpl16(*left);
            *left = tables.cpl16(*right);
            *right = tmp;
            left = left.offset(1);
            right = right.offset(-1);
        }

        let end = end as *mut u8;
        match rem {
            1 => *end = tables.cpl8(*end),
            2 => {
                let tmp = tables.cpl8(*end);
                *end = tables.cpl8(*end.offset(1));
                *end.offset(1) = tmp;
            },
            3 => {
                *end.offset(1) = tables.cpl8(*end.offset(1));
                let tmp = tables.cpl8(*end);
                *end = tables.cpl8(*end.offset(2));
                *end.offset(2) = tmp;
            },
            _ => { },
        }
    }
}

struct Racy<T>(T);
unsafe impl<T: 'static> Send for Racy<T> {}

/// Executes a closure in parallel over the given iterator over mutable slice.
/// The closure `f` is run in parallel with an element of `iter`.
fn parallel<'a, I, T, F>(iter: I, ref f: F)
        where T: 'static + Send + Sync,
              I: Iterator<Item=&'a mut [T]>,
              F: Fn(&mut [T]) + Sync {
    let jhs = iter.map(|chunk| {
        // Need to convert `f` and `chunk` to something that can cross the task
        // boundary.
        let f = Racy(f as *const F as *const usize);
        let raw = Racy((&mut chunk[0] as *mut T, chunk.len()));
        thread::spawn(move|| {
            let f = f.0 as *const F;
            let raw = raw.0;
            unsafe { (*f)(std::slice::from_raw_parts_mut(raw.0, raw.1)) }
        })
    }).collect::<Vec<_>>();
    for jh in jhs { jh.join().unwrap(); }
}

fn main() {
    let stdin = std::io::stdin();
    let mut data = Vec::with_capacity(1024 * 1024);
    stdin.lock().read_to_end(&mut data).unwrap();
    let tables = &Tables::new();
    parallel(mut_dna_seqs(&mut data), |seq| reverse_complement(seq, tables));
    let stdout = std::io::stdout();
    stdout.lock().write_all(&data).unwrap();
}
<|endoftext|>