<commit_before>extern crate serde_json;
extern crate clap;

use serde_json::Value;
use serde_json::Deserializer;
use std::io;
use clap::{App, Arg};
use std::fs;

fn main() {

    let matches = App::new("jp").version("0.1")
        .about("Extract JSON elements from a stream")
        .author("Brian McCallister <brianm@skife.org>")
        .arg(Arg::with_name("INPUT").index(1).help("input file to use if not receiving on stdin"))
        .get_matches();

    let input = matches.value_of("INPUT").unwrap_or("-");
    let rdr: Box<io::Read> = match input {
        "-" => Box::new(io::stdin()),
        _   => Box::new(fs::File::open(input).unwrap())
    };

    let iter = Deserializer::from_reader(rdr).into_iter::<Value>();
    for rv in iter {
        let v: Value = rv.unwrap();
        println!("{}\t{}",
                 v.pointer("/name").unwrap(),
                 v.pointer("/age").unwrap());
    }
}
<commit_msg>initial<commit_after>extern crate serde_json;
extern crate clap;

use serde_json::Value;
use serde_json::Deserializer;
use std::io;
use clap::{App, Arg};
use std::fs;

fn main() {

    let matches = App::new("jp").version("0.1")
        .about("Extract JSON elements from a stream")
        .author("Brian McCallister <brianm@skife.org>")
        .arg(Arg::with_name("INPUT").index(1).help("input file to use if not receiving on stdin"))
        .get_matches();

    let input = matches.value_of("INPUT").unwrap_or("-");
    let rdr: io::Read = match input {
        "-" => io::stdin(),
        _   => fs::File::open(input).unwrap()
    };

    let iter = Deserializer::from_reader(rdr).into_iter::<Value>();
    for rv in iter {
        let v: Value = rv.unwrap();
        println!("{}\t{}",
                 v.pointer("/name").unwrap(),
                 v.pointer("/age").unwrap());
    }
}
<|endoftext|>


<commit_before>#![feature(plugin, proc_macro)]
extern crate postgres;

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;

extern crate getopts;

use postgres::{Connection, TlsMode};

use std::env;
use getopts::Options;
use std::fs;
use std::fs::File;
use std::io::{Write, BufWriter};
use std::collections::HashMap;
use std::rc::Rc;

mod pombase;

use pombase::web::data::*;
use pombase::db::*;

fn make_term_short(rc_cvterm: Rc<pombase::db::Cvterm>) -> TermShort {
    TermShort {
        name: rc_cvterm.name.clone(),
        termid: rc_cvterm.termid(),
        is_obsolete: rc_cvterm.is_obsolete
    }
}

fn make_gene_short(gene_details: &GeneDetails) -> GeneShort {
    GeneShort {
        uniquename: gene_details.uniquename.clone(),
        name: gene_details.name.clone(),
    }
}

fn make_publication_short(rc_publication: Rc<pombase::db::Publication>) -> Option<PublicationShort> {
    if rc_publication.uniquename == "null" {
        None
    } else {
        Some(PublicationShort {
            uniquename: rc_publication.uniquename.clone(),
            title: rc_publication.title.clone(),
            citation: rc_publication.miniref.clone(),
        })
    }
}

#[derive(Serialize)]
struct WebData {
    genes: IdGeneMap,
    terms: IdTermMap,
    used_terms: IdTermMap,
    metadata: Metadata,
}

fn get_web_data(raw: &Raw, organism_genus_species: &String) -> WebData {
    let mut genes: UniquenameGeneMap = HashMap::new();
    let mut transcripts: UniquenameTranscriptMap = HashMap::new();
    let mut genotypes: UniquenameGenotypeMap = HashMap::new();
    let mut alleles: UniquenameAlleleShortMap = HashMap::new();
    let mut terms: IdTermMap = HashMap::new();

    let mut genes_of_transcripts: HashMap<String, String> = HashMap::new();
    let mut genes_of_alleles: HashMap<String, String> = HashMap::new();
    let mut alleles_of_genotypes: HashMap<String, Vec<String>> = HashMap::new();

    for feature_rel in raw.feature_relationships.iter() {
        let subject_type_name = &feature_rel.subject.feat_type.name;
        let rel_name = &feature_rel.rel_type.name;
        let object_type_name = &feature_rel.object.feat_type.name;
        let subject_uniquename = &feature_rel.subject.uniquename;
        let object_uniquename = &feature_rel.object.uniquename;

        if subject_type_name == "mRNA" &&
            rel_name == "part_of" &&
            object_type_name == "gene" {
                genes_of_transcripts.insert(subject_uniquename.clone(),
                                            object_uniquename.clone());
        }
        if subject_type_name == "allele" {
            if feature_rel.rel_type.name == "instance_of" &&
                object_type_name == "gene" {
                    genes_of_alleles.insert(subject_uniquename.clone(), object_uniquename.clone());
                }
            if feature_rel.rel_type.name == "part_of" &&
                object_type_name == "genotype" {
                    let entry = alleles_of_genotypes.entry(object_uniquename.clone());
                    entry.or_insert(Vec::new()).push(subject_uniquename.clone());
                }
        }
    }

//    type IdAnnotationMap = HashMap<i32, (FeatureAnnotation, TermAnnotation)>;

//    let annotation_map: IdAnnotationMap = HashMap::new();

    for feat in raw.features.iter().filter(|&f| {
        let feature_org_genus_species = String::new() +
            &f.organism.genus + "_" + &f.organism.species;
        feature_org_genus_species == *organism_genus_species
    } ) {

        match &feat.feat_type.name as &str {
            "gene" => {
                genes.insert(feat.uniquename.clone(),
                             GeneDetails {
                                 uniquename: feat.uniquename.clone(),
                                 name: feat.name.clone(),
                                 annotations: HashMap::new(),
                                 transcripts: vec![],
                             });
                ()},
            // TODO: mRNA isn't the only transcript type
            "mRNA" => {
                transcripts.insert(feat.uniquename.clone(),
                                   TranscriptDetails {
                                       uniquename: feat.uniquename.clone(),
                                       name: feat.name.clone(),
//                                       annotations: HashMap::new(),
                                   });
                ()},
            "genotype" => {
                genotypes.insert(feat.uniquename.clone(),
                                 GenotypeDetails {
                                     uniquename: feat.uniquename.clone(),
                                     name: feat.name.clone(),
                                     annotations: HashMap::new(),
                                 });
                ()},
            "allele" => {
                let gene_uniquename =
                    genes_of_alleles.get(&feat.uniquename).unwrap();
                alleles.insert(feat.uniquename.clone(),
                               AlleleShort {
                                   uniquename: feat.uniquename.clone(),
                                   name: feat.name.clone(),
                                   gene_uniquename: gene_uniquename.clone(),
                               });
                ()},
            _ => (),
        }
    }

    for cvterm in &raw.cvterms {
        terms.insert(cvterm.termid(),
                     TermDetails {
                         name: cvterm.name.clone(),
                         termid: cvterm.termid(),
                         definition: cvterm.definition.clone(),
                         is_obsolete: cvterm.is_obsolete,
                         annotations: vec![],
                     });
    }

    for feature_cvterm in raw.feature_cvterms.iter() {
        let feature = &feature_cvterm.feature;
        let cvterm = &feature_cvterm.cvterm;
        let mut evidence: Option<String> = None;
        for prop in feature_cvterm.feature_cvtermprops.borrow().iter() {
            if (*prop).type_name() == "evidence" {
                evidence = prop.value.clone();
            }
        }
        let publication = make_publication_short(feature_cvterm.publication.clone());
        let mut genotype_alleles = None;
        let gene_uniquenames_vec: Vec<GeneUniquename> =
            if feature.feat_type.name == "mRNA" {
                if let Some(gene_uniquename) = genes_of_transcripts.get(&feature.uniquename) {
                    vec![gene_uniquename.clone()]
                } else {
                    vec![]
                }
            } else {
                if feature.feat_type.name == "genotype" {
                    if let Some(allele_uniquenames_vec) =
                        alleles_of_genotypes.get(&feature.uniquename) {
                            let genotype_alleles_ret = GenotypeAndAlleles {
                                alleles: allele_uniquenames_vec.iter()
                                    .map(|allele_uniquename| alleles.get(allele_uniquename).unwrap().clone())
                                    .collect::<Vec<_>>()
                            };
                            genotype_alleles = Some(genotype_alleles_ret);
                            allele_uniquenames_vec.iter()
                                .map(|allele_uniquename|
                                     {
                                         let gene_uniquename = genes_of_alleles.get(allele_uniquename).unwrap();
                                         gene_uniquename.clone()
                                     })
                                .collect()
                    } else {
                        vec![]
                    }
                } else {
                    if feature.feat_type.name == "gene" {
                        vec![feature.uniquename.clone()]
                    } else {
                        vec![]
                    }
                }
            };

        for gene_uniquename in &gene_uniquenames_vec {
            let feature_annotation =
                FeatureAnnotation {
                    term: make_term_short(cvterm.clone()),
                    evidence: evidence.clone(),
                    publication: publication.clone(),
                    genotype: genotype_alleles.clone(),
                };
            let cv_name = cvterm.cv.name.clone();
            let mut gene_details = genes.get_mut(gene_uniquename).unwrap();
            gene_details.annotations.entry(cv_name).or_insert(Vec::new()).push(feature_annotation);
            let term_annotation =
                TermAnnotation {
                    gene: make_gene_short(&gene_details),
                    evidence: evidence.clone(),
                    publication: publication.clone(),
                };
            let termid = cvterm.termid();
            let term_details = terms.get_mut(&termid).unwrap();
            term_details.annotations.push(term_annotation);
        }
    }

    // remove terms with no annotation
    let used_terms = terms.clone().into_iter()
        .filter(|&(_, ref t)| t.annotations.len() > 0)
        .collect();

    let mut db_creation_datetime = None;

    for chadoprop in &raw.chadoprops {
        if chadoprop.prop_type.name == "db_creation_datetime" {
            db_creation_datetime = chadoprop.value.clone();
        }
    }

    let metadata = Metadata {
        db_creation_datetime: db_creation_datetime.unwrap(),
        gene_count: genes.len(),
        term_count: terms.len(),
    };

    WebData {
        genes: genes,
        terms: terms,
        used_terms: used_terms,
        metadata: metadata,
    }
}

fn write_genes(output_dir: &str, genes: &IdGeneMap) {
    let s = serde_json::to_string(&genes).unwrap();
    let file_name = String::new() + &output_dir + "/genes.json";
    let f = File::create(file_name).expect("Unable to open file");
    let mut writer = BufWriter::new(&f);
    writer.write_all(s.as_bytes()).expect("Unable to write!");

    for (gene_uniquename, gene_details) in genes {
        let s = serde_json::to_string(&gene_details).unwrap();
        let file_name = String::new() + &output_dir + "/gene/" + &gene_uniquename + ".json";
        let f = File::create(file_name).expect("Unable to open file");
        let mut writer = BufWriter::new(&f);
        writer.write_all(s.as_bytes()).expect("Unable to write!");
    }
}

fn write_terms(output_dir: &str, terms: &IdTermMap) {
    let s = serde_json::to_string(&terms).unwrap();
    let file_name = String::new() + &output_dir + "/terms.json";
    let f = File::create(file_name).expect("Unable to open file");
    let mut writer = BufWriter::new(&f);
    writer.write_all(s.as_bytes()).expect("Unable to write!");

    for (termid, term_details) in terms {
        let s = serde_json::to_string(&term_details).unwrap();
        let file_name = String::new() + &output_dir + "/term/" + &termid + ".json";
        let f = File::create(file_name).expect("Unable to open file");
        let mut writer = BufWriter::new(&f);
        writer.write_all(s.as_bytes()).expect("Unable to write!");
    }
}

fn write_metadata(output_dir: &str, metadata: &Metadata) {
    let s = serde_json::to_string(&metadata).unwrap();
    let file_name = String::new() + &output_dir + "/metadata.json";
    let f = File::create(file_name).expect("Unable to open file");
    let mut writer = BufWriter::new(&f);
    writer.write_all(s.as_bytes()).expect("Unable to write!");
}

fn write_web_data(output_dir: &str, web_data: &WebData) {
    let s = serde_json::to_string(&web_data).unwrap();
    let file_name = String::new() + output_dir + "/all.json";
    let f = File::create(file_name).expect("Unable to open file");
    let mut writer = BufWriter::new(&f);
    writer.write_all(s.as_bytes()).expect("Unable to write!");

    write_genes(output_dir, &web_data.genes);
    write_terms(output_dir, &web_data.terms);
    write_metadata(output_dir, &web_data.metadata);

    println!("wrote {} genes", web_data.genes.len());
    println!("wrote {} terms", web_data.terms.len());
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.reqopt("c", "connection-string",
                "PostgresSQL connection string like: postgres://user:pass@host/db_name",
                "CONN_STR");
    opts.reqopt("d", "output-directory",
                "Destination directory for JSON output", "DIR");
    opts.reqopt("O", "organism",
                "Only output genes from this organism (eg. 'Schizosaccharomyces_pombe')", "GENUS_SPECIES");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };

    let connection_string = matches.opt_str("c").unwrap();
    let output_dir = matches.opt_str("d").unwrap();
    let organism_genus_species = matches.opt_str("O").unwrap();

    let subdirs = vec!["gene", "term"];

    for subdir in &subdirs {
        let dir = String::new() + &output_dir + "/" + subdir;
        fs::create_dir_all(&dir).unwrap_or_else(|why| {
            println!("Creating output directory failed: {:?}", why.kind());
        });
    }

    let conn = Connection::connect(connection_string.as_str(), TlsMode::None).unwrap();
    let raw = Raw::new(&conn);
    let web_data = get_web_data(&raw, &organism_genus_species);

    write_web_data(&output_dir, &web_data);
}
<commit_msg>Simplify code<commit_after>#![feature(plugin, proc_macro)]
extern crate postgres;

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;

extern crate getopts;

use postgres::{Connection, TlsMode};

use std::env;
use getopts::Options;
use std::fs;
use std::fs::File;
use std::io::{Write, BufWriter};
use std::collections::HashMap;
use std::rc::Rc;

mod pombase;

use pombase::web::data::*;
use pombase::db::*;

fn make_term_short(rc_cvterm: Rc<pombase::db::Cvterm>) -> TermShort {
    TermShort {
        name: rc_cvterm.name.clone(),
        termid: rc_cvterm.termid(),
        is_obsolete: rc_cvterm.is_obsolete
    }
}

fn make_gene_short(gene_details: &GeneDetails) -> GeneShort {
    GeneShort {
        uniquename: gene_details.uniquename.clone(),
        name: gene_details.name.clone(),
    }
}

fn make_publication_short(rc_publication: Rc<pombase::db::Publication>) -> Option<PublicationShort> {
    if rc_publication.uniquename == "null" {
        None
    } else {
        Some(PublicationShort {
            uniquename: rc_publication.uniquename.clone(),
            title: rc_publication.title.clone(),
            citation: rc_publication.miniref.clone(),
        })
    }
}

#[derive(Serialize)]
struct WebData {
    genes: IdGeneMap,
    terms: IdTermMap,
    used_terms: IdTermMap,
    metadata: Metadata,
}

fn get_web_data(raw: &Raw, organism_genus_species: &String) -> WebData {
    let mut genes: UniquenameGeneMap = HashMap::new();
    let mut transcripts: UniquenameTranscriptMap = HashMap::new();
    let mut genotypes: UniquenameGenotypeMap = HashMap::new();
    let mut alleles: UniquenameAlleleShortMap = HashMap::new();
    let mut terms: IdTermMap = HashMap::new();

    let mut genes_of_transcripts: HashMap<String, String> = HashMap::new();
    let mut genes_of_alleles: HashMap<String, String> = HashMap::new();
    let mut alleles_of_genotypes: HashMap<String, Vec<String>> = HashMap::new();

    for feature_rel in raw.feature_relationships.iter() {
        let subject_type_name = &feature_rel.subject.feat_type.name;
        let rel_name = &feature_rel.rel_type.name;
        let object_type_name = &feature_rel.object.feat_type.name;
        let subject_uniquename = &feature_rel.subject.uniquename;
        let object_uniquename = &feature_rel.object.uniquename;

        if subject_type_name == "mRNA" &&
            rel_name == "part_of" &&
            object_type_name == "gene" {
                genes_of_transcripts.insert(subject_uniquename.clone(),
                                            object_uniquename.clone());
        }
        if subject_type_name == "allele" {
            if feature_rel.rel_type.name == "instance_of" &&
                object_type_name == "gene" {
                    genes_of_alleles.insert(subject_uniquename.clone(), object_uniquename.clone());
                }
            if feature_rel.rel_type.name == "part_of" &&
                object_type_name == "genotype" {
                    let entry = alleles_of_genotypes.entry(object_uniquename.clone());
                    entry.or_insert(Vec::new()).push(subject_uniquename.clone());
                }
        }
    }

//    type IdAnnotationMap = HashMap<i32, (FeatureAnnotation, TermAnnotation)>;

//    let annotation_map: IdAnnotationMap = HashMap::new();

    for feat in raw.features.iter().filter(|&f| {
        let feature_org_genus_species = String::new() +
            &f.organism.genus + "_" + &f.organism.species;
        feature_org_genus_species == *organism_genus_species
    } ) {

        match &feat.feat_type.name as &str {
            "gene" => {
                genes.insert(feat.uniquename.clone(),
                             GeneDetails {
                                 uniquename: feat.uniquename.clone(),
                                 name: feat.name.clone(),
                                 annotations: HashMap::new(),
                                 transcripts: vec![],
                             });
            },
            // TODO: mRNA isn't the only transcript type
            "mRNA" => {
                transcripts.insert(feat.uniquename.clone(),
                                   TranscriptDetails {
                                       uniquename: feat.uniquename.clone(),
                                       name: feat.name.clone(),
//                                       annotations: HashMap::new(),
                                   });
            },
            "genotype" => {
                genotypes.insert(feat.uniquename.clone(),
                                 GenotypeDetails {
                                     uniquename: feat.uniquename.clone(),
                                     name: feat.name.clone(),
                                     annotations: HashMap::new(),
                                 });
            },
            "allele" => {
                let gene_uniquename =
                    genes_of_alleles.get(&feat.uniquename).unwrap();
                alleles.insert(feat.uniquename.clone(),
                               AlleleShort {
                                   uniquename: feat.uniquename.clone(),
                                   name: feat.name.clone(),
                                   gene_uniquename: gene_uniquename.clone(),
                               });
            },
            _ => (),
        }
    }

    for cvterm in &raw.cvterms {
        terms.insert(cvterm.termid(),
                     TermDetails {
                         name: cvterm.name.clone(),
                         termid: cvterm.termid(),
                         definition: cvterm.definition.clone(),
                         is_obsolete: cvterm.is_obsolete,
                         annotations: vec![],
                     });
    }

    for feature_cvterm in raw.feature_cvterms.iter() {
        let feature = &feature_cvterm.feature;
        let cvterm = &feature_cvterm.cvterm;
        let mut evidence: Option<String> = None;
        for prop in feature_cvterm.feature_cvtermprops.borrow().iter() {
            if (*prop).type_name() == "evidence" {
                evidence = prop.value.clone();
            }
        }
        let publication = make_publication_short(feature_cvterm.publication.clone());
        let mut genotype_alleles = None;
        let gene_uniquenames_vec: Vec<GeneUniquename> =
            if feature.feat_type.name == "mRNA" {
                if let Some(gene_uniquename) = genes_of_transcripts.get(&feature.uniquename) {
                    vec![gene_uniquename.clone()]
                } else {
                    vec![]
                }
            } else {
                if feature.feat_type.name == "genotype" {
                    if let Some(allele_uniquenames_vec) =
                        alleles_of_genotypes.get(&feature.uniquename) {
                            let genotype_alleles_ret = GenotypeAndAlleles {
                                alleles: allele_uniquenames_vec.iter()
                                    .map(|allele_uniquename| alleles.get(allele_uniquename).unwrap().clone())
                                    .collect::<Vec<_>>()
                            };
                            genotype_alleles = Some(genotype_alleles_ret);
                            allele_uniquenames_vec.iter()
                                .map(|allele_uniquename|
                                     {
                                         let gene_uniquename = genes_of_alleles.get(allele_uniquename).unwrap();
                                         gene_uniquename.clone()
                                     })
                                .collect()
                    } else {
                        vec![]
                    }
                } else {
                    if feature.feat_type.name == "gene" {
                        vec![feature.uniquename.clone()]
                    } else {
                        vec![]
                    }
                }
            };

        for gene_uniquename in &gene_uniquenames_vec {
            let feature_annotation =
                FeatureAnnotation {
                    term: make_term_short(cvterm.clone()),
                    evidence: evidence.clone(),
                    publication: publication.clone(),
                    genotype: genotype_alleles.clone(),
                };
            let cv_name = cvterm.cv.name.clone();
            let mut gene_details = genes.get_mut(gene_uniquename).unwrap();
            gene_details.annotations.entry(cv_name).or_insert(Vec::new()).push(feature_annotation);
            let term_annotation =
                TermAnnotation {
                    gene: make_gene_short(&gene_details),
                    evidence: evidence.clone(),
                    publication: publication.clone(),
                };
            let termid = cvterm.termid();
            let term_details = terms.get_mut(&termid).unwrap();
            term_details.annotations.push(term_annotation);
        }
    }

    // remove terms with no annotation
    let used_terms = terms.clone().into_iter()
        .filter(|&(_, ref t)| t.annotations.len() > 0)
        .collect();

    let mut db_creation_datetime = None;

    for chadoprop in &raw.chadoprops {
        if chadoprop.prop_type.name == "db_creation_datetime" {
            db_creation_datetime = chadoprop.value.clone();
        }
    }

    let metadata = Metadata {
        db_creation_datetime: db_creation_datetime.unwrap(),
        gene_count: genes.len(),
        term_count: terms.len(),
    };

    WebData {
        genes: genes,
        terms: terms,
        used_terms: used_terms,
        metadata: metadata,
    }
}

fn write_genes(output_dir: &str, genes: &IdGeneMap) {
    let s = serde_json::to_string(&genes).unwrap();
    let file_name = String::new() + &output_dir + "/genes.json";
    let f = File::create(file_name).expect("Unable to open file");
    let mut writer = BufWriter::new(&f);
    writer.write_all(s.as_bytes()).expect("Unable to write!");

    for (gene_uniquename, gene_details) in genes {
        let s = serde_json::to_string(&gene_details).unwrap();
        let file_name = String::new() + &output_dir + "/gene/" + &gene_uniquename + ".json";
        let f = File::create(file_name).expect("Unable to open file");
        let mut writer = BufWriter::new(&f);
        writer.write_all(s.as_bytes()).expect("Unable to write!");
    }
}

fn write_terms(output_dir: &str, terms: &IdTermMap) {
    let s = serde_json::to_string(&terms).unwrap();
    let file_name = String::new() + &output_dir + "/terms.json";
    let f = File::create(file_name).expect("Unable to open file");
    let mut writer = BufWriter::new(&f);
    writer.write_all(s.as_bytes()).expect("Unable to write!");

    for (termid, term_details) in terms {
        let s = serde_json::to_string(&term_details).unwrap();
        let file_name = String::new() + &output_dir + "/term/" + &termid + ".json";
        let f = File::create(file_name).expect("Unable to open file");
        let mut writer = BufWriter::new(&f);
        writer.write_all(s.as_bytes()).expect("Unable to write!");
    }
}

fn write_metadata(output_dir: &str, metadata: &Metadata) {
    let s = serde_json::to_string(&metadata).unwrap();
    let file_name = String::new() + &output_dir + "/metadata.json";
    let f = File::create(file_name).expect("Unable to open file");
    let mut writer = BufWriter::new(&f);
    writer.write_all(s.as_bytes()).expect("Unable to write!");
}

fn write_web_data(output_dir: &str, web_data: &WebData) {
    let s = serde_json::to_string(&web_data).unwrap();
    let file_name = String::new() + output_dir + "/all.json";
    let f = File::create(file_name).expect("Unable to open file");
    let mut writer = BufWriter::new(&f);
    writer.write_all(s.as_bytes()).expect("Unable to write!");

    write_genes(output_dir, &web_data.genes);
    write_terms(output_dir, &web_data.terms);
    write_metadata(output_dir, &web_data.metadata);

    println!("wrote {} genes", web_data.genes.len());
    println!("wrote {} terms", web_data.terms.len());
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.reqopt("c", "connection-string",
                "PostgresSQL connection string like: postgres://user:pass@host/db_name",
                "CONN_STR");
    opts.reqopt("d", "output-directory",
                "Destination directory for JSON output", "DIR");
    opts.reqopt("O", "organism",
                "Only output genes from this organism (eg. 'Schizosaccharomyces_pombe')", "GENUS_SPECIES");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };

    let connection_string = matches.opt_str("c").unwrap();
    let output_dir = matches.opt_str("d").unwrap();
    let organism_genus_species = matches.opt_str("O").unwrap();

    let subdirs = vec!["gene", "term"];

    for subdir in &subdirs {
        let dir = String::new() + &output_dir + "/" + subdir;
        fs::create_dir_all(&dir).unwrap_or_else(|why| {
            println!("Creating output directory failed: {:?}", why.kind());
        });
    }

    let conn = Connection::connect(connection_string.as_str(), TlsMode::None).unwrap();
    let raw = Raw::new(&conn);
    let web_data = get_web_data(&raw, &organism_genus_species);

    write_web_data(&output_dir, &web_data);
}
<|endoftext|>


<commit_before>//! Coredump implementation of the Space API server.
//!
//! Start this via the commandline:
//!
//!     ./coredump_status [-p PORT] [-i IP]
extern crate env_logger;
extern crate docopt;
extern crate rustc_serialize;
extern crate spaceapi_server;

mod utils;

use std::sync::{Arc, Mutex};
use docopt::Docopt;
use spaceapi_server::SpaceapiServer;
use spaceapi_server::api;
use spaceapi_server::api::sensors::{TemperatureSensorTemplate, PeopleNowPresentSensorTemplate};
use spaceapi_server::api::Optional::{Value, Absent};
use spaceapi_server::datastore::{DataStore, RedisStore};
use utils::Ipv4;

static USAGE: &'static str = "
Usage: coredump_status [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 3000].
    -i IP    The ipv4 address to listen on [default: 127.0.0.1].
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_p: u16,
    flag_i: Ipv4,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init().unwrap();

    // Parse arguments
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i.ip;
    let port = args.flag_p;

    // Create new Status instance
    let mut status = api::Status::new(
        "coredump",
        "https://www.coredump.ch/logo.png",
        "https://www.coredump.ch/",
        api::Location {
            address: Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".into()),
            lat: 47.22936,
            lon: 8.82949,
        },
        api::Contact {
            irc: Value("irc://freenode.net/#coredump".into()),
            twitter: Value("@coredump_ch".into()),
            foursquare: Value("525c20e5498e875d8231b1e5".into()),
            email: Value("vorstand@lists.coredump.ch".into()),
        },
        vec![
            "email".into(),
            "twitter".into(),
        ],
    );

    // Add optional data
    status.spacefed = Value(api::Spacefed {
        spacenet: false,
        spacesaml: false,
        spacephone: false,
    });
    status.feeds = Value(api::Feeds {
        blog: Value(api::Feed {
            _type: Value("rss".into()),
            url: "https://www.coredump.ch/feed/".into(),
        }),
        wiki: Absent,
        calendar: Absent,
        flickr: Absent,
    });
    status.projects = Value(vec![
        "https://www.coredump.ch/projekte/".into(),
        "https://discourse.coredump.ch/c/projects".into(),
        "https://github.com/coredump-ch/".into(),
    ]);
    status.cam = Value(vec![
        "https://webcam.coredump.ch/cams/ultimaker.jpg".into(),
    ]);
    status.state.message = Value("Open every Monday from 20:00".into());

    // Set up datastore
    let datastore = Arc::new(Mutex::new(Box::new(RedisStore::new().unwrap()) as Box<DataStore>));

    // Set up server
    let mut server = SpaceapiServer::new(host, port, status, datastore);

    // Register sensors
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".into(),
        location: "Hackerspace".into(),
        name: Value("Raspberry CPU".into()),
        description: Absent,
    }), "raspi_temperature".into());
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".into(),
        location: "Hackerspace".into(),
        name: Value("Room Temperature".into()),
        description: Absent,
    }), "room_temperature".into());
    server.register_sensor(Box::new(PeopleNowPresentSensorTemplate {
        location: Value("Hackerspace".into()),
        name: Absent,
        description: Absent,
        names: Absent,
    }), "people_present".into());

    // Serve!
    server.serve();
}
<commit_msg>Add new Paths for Webcams<commit_after>//! Coredump implementation of the Space API server.
//!
//! Start this via the commandline:
//!
//!     ./coredump_status [-p PORT] [-i IP]
extern crate env_logger;
extern crate docopt;
extern crate rustc_serialize;
extern crate spaceapi_server;

mod utils;

use std::sync::{Arc, Mutex};
use docopt::Docopt;
use spaceapi_server::SpaceapiServer;
use spaceapi_server::api;
use spaceapi_server::api::sensors::{TemperatureSensorTemplate, PeopleNowPresentSensorTemplate};
use spaceapi_server::api::Optional::{Value, Absent};
use spaceapi_server::datastore::{DataStore, RedisStore};
use utils::Ipv4;

static USAGE: &'static str = "
Usage: coredump_status [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 3000].
    -i IP    The ipv4 address to listen on [default: 127.0.0.1].
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_p: u16,
    flag_i: Ipv4,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init().unwrap();

    // Parse arguments
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i.ip;
    let port = args.flag_p;

    // Create new Status instance
    let mut status = api::Status::new(
        "coredump",
        "https://www.coredump.ch/logo.png",
        "https://www.coredump.ch/",
        api::Location {
            address: Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".into()),
            lat: 47.22936,
            lon: 8.82949,
        },
        api::Contact {
            irc: Value("irc://freenode.net/#coredump".into()),
            twitter: Value("@coredump_ch".into()),
            foursquare: Value("525c20e5498e875d8231b1e5".into()),
            email: Value("vorstand@lists.coredump.ch".into()),
        },
        vec![
            "email".into(),
            "twitter".into(),
        ],
    );

    // Add optional data
    status.spacefed = Value(api::Spacefed {
        spacenet: false,
        spacesaml: false,
        spacephone: false,
    });
    status.feeds = Value(api::Feeds {
        blog: Value(api::Feed {
            _type: Value("rss".into()),
            url: "https://www.coredump.ch/feed/".into(),
        }),
        wiki: Absent,
        calendar: Absent,
        flickr: Absent,
    });
    status.projects = Value(vec![
        "https://www.coredump.ch/projekte/".into(),
        "https://discourse.coredump.ch/c/projects".into(),
        "https://github.com/coredump-ch/".into(),
    ]);
    status.cam = Value(vec![
        "https://webcam.coredump.ch/cams/ultimaker_0.jpg".into(),
        "https://webcam.coredump.ch/cams/ultimaker_1.jpg".into(),
    ]);
    status.state.message = Value("Open every Monday from 20:00".into());

    // Set up datastore
    let datastore = Arc::new(Mutex::new(Box::new(RedisStore::new().unwrap()) as Box<DataStore>));

    // Set up server
    let mut server = SpaceapiServer::new(host, port, status, datastore);

    // Register sensors
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".into(),
        location: "Hackerspace".into(),
        name: Value("Raspberry CPU".into()),
        description: Absent,
    }), "raspi_temperature".into());
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".into(),
        location: "Hackerspace".into(),
        name: Value("Room Temperature".into()),
        description: Absent,
    }), "room_temperature".into());
    server.register_sensor(Box::new(PeopleNowPresentSensorTemplate {
        location: Value("Hackerspace".into()),
        name: Absent,
        description: Absent,
        names: Absent,
    }), "people_present".into());

    // Serve!
    server.serve();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate mhost;
extern crate resolv_conf;
extern crate tokio_core;
extern crate trust_dns;

use mhost::{multiple_lookup, DnsQuery};

use clap::{App, Arg, ArgMatches, Shell};
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::net::IpAddr;
use std::str::FromStr;
use std::time::Duration;
use tokio_core::reactor::Core;
use trust_dns::rr::{RData, RecordType};

// Arbitrary list of public DNS servers
static DEFAULT_DNS_SERVERS: &'static [&str] = &[
    // "Level3",
    "209.244.0.3",
    "209.244.0.4",
    // "Verisign",
    "64.6.64.6",
    "64.6.65.6",
    // "Google",
    "8.8.8.8",
    "8.8.4.4",
    // "DNS.WATCH",
    "84.200.69.80",
    "84.200.70.40",
    // "OpenDNS Home",
    "208.67.222.222",
    "208.67.220.220",
    // "SafeDNS",
    "195.46.39.39",
    "195.46.39.40",
    // "Dyn",
    "216.146.35.35",
    "216.146.36.36",
    // "FreeDNS",
    "37.235.1.174",
    "37.235.1.177",
    // "Alternate DNS",
    "198.101.242.72",
    "23.253.163.53",
];

static DEFAULT_RECORD_TYPES: &'static [&str] = &["a", "aaaa", "mx"];

fn run() -> Result<()> {
    let args = build_cli().get_matches();

    if args.is_present("completions") {
        return generate_completion(&args);
    }

    let dns_endpoints = get_dns_servers(&args)
        .chain_err(|| ErrorKind::ServerIpAddrParsingError)?
        .into_iter()
        .map(|s| (s, 53))
        .collect();

    let timeout = value_t!(args, "timeout", u64)
        .map(Duration::from_secs)
        .unwrap();

    let mut query = match IpAddr::from_str(args.value_of("domain name").unwrap()) {
        Ok(ip) => DnsQuery::from(ip, vec![RecordType::PTR]),
        Err(_) => {
            let record_types = get_record_types(&args).chain_err(|| {
                ErrorKind::ResoureRecordTypeParsingError
            })?;
            DnsQuery::new(args.value_of("domain name").unwrap(), record_types)
        }
    };
    query = query.set_timeout(timeout);

    let mut io_loop = Core::new().unwrap();
    let lookup = multiple_lookup(&io_loop.handle(), query, dns_endpoints);
    let result = io_loop.run(lookup);

    match result {
        Ok(ref responses) => {
            for response in responses {
                match *response {
                    Ok(ref x) => println!("{}", DnsResponse(x)),
                    Err(ref e) => println!("Error: {}", e),
                }
            }
        }
        Err(_) => {
            println!("General Error");
        }
    }

    Ok(())
}

fn build_cli() -> App<'static, 'static> {
    let name = env!("CARGO_PKG_NAME");
    let version = env!("CARGO_PKG_VERSION");
    let about = env!("CARGO_PKG_DESCRIPTION");

    App::new(name)
        .version(version)
        .about(about)
        .arg(
            Arg::with_name("domain name")
                .index(1)
                .required(true)
                .conflicts_with("completions")
                .help("domain name or IP address to look up"),
        )
        .arg(
            Arg::with_name("timeout")
                .long("timeout")
                .default_value("5")
                .help("timeout for server responses in sec")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("record types")
                .long("type")
                .short("t")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1)
                .possible_values(
                    &[
                        "a",
                        "aaaa",
                        "any",
                        "cname",
                        "dnskey",
                        "mx",
                        "ns",
                        "opt",
                        "ptr",
                        "soa",
                        "srv",
                        "txt",
                    ],
                )
                .help("Select resource record type [default: a, aaaa, mx]"),
        )
        .arg(
            Arg::with_name("dont use local dns servers")
                .short("L")
                .help("Do not use local (/etc/resolv.conf) DNS servers"),
        )
        .arg(Arg::with_name("predefined server").short("S").help(
            "use predefined DNS server set",
        ))
        .arg(
            Arg::with_name("DNS servers")
                .long("server")
                .short("s")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1)
                .help(
                    "DNS servers to use; if empty use predefined, public DNS server",
                ),
        )
        .arg(
            Arg::with_name("completions")
                .long("completions")
                .takes_value(true)
                .hidden(true)
                .possible_values(&["bash", "fish", "zsh"])
                .help("The shell to generate the script for"),
        )
}

fn generate_completion(args: &ArgMatches) -> Result<()> {
    let bin_name = env!("CARGO_PKG_NAME");
    let shell = args.value_of("completions").ok_or(
        ErrorKind::CliArgsParsingError,
    )?;
    build_cli().gen_completions_to(
        bin_name,
        shell.parse::<Shell>().unwrap(),
        &mut std::io::stdout(),
    );
    Ok(())
}

fn get_local_dns_servers() -> Result<Vec<IpAddr>> {
    let mut buf = Vec::with_capacity(4096);
    let mut f = File::open("/etc/resolv.conf").chain_err(
        || ErrorKind::ResolvConfError,
    )?;
    f.read_to_end(&mut buf).unwrap();
    let cfg = resolv_conf::Config::parse(&buf[..]).chain_err(|| {
        ErrorKind::ResolvConfError
    })?;
    Ok(cfg.nameservers)
}

fn get_dns_servers(args: &ArgMatches) -> Result<Vec<IpAddr>> {
    let mut dns_servers: Vec<IpAddr> = Vec::new();
    if let Some(servers) = args.values_of_lossy("DNS servers") {
        dns_servers.extend(servers.into_iter().map(|server| {
            IpAddr::from_str(&server).unwrap()
        }));
    }
    if args.is_present("predefined server") {
        dns_servers.extend(DEFAULT_DNS_SERVERS.iter().map(|server| {
            IpAddr::from_str(server).unwrap()
        }));
    }
    if !args.is_present("dont use local dns servers") {
        dns_servers.extend(get_local_dns_servers()?);
    }

    Ok(dns_servers)
}

fn get_record_types(args: &ArgMatches) -> Result<Vec<RecordType>> {
    let record_types = if let Some(record_types) = args.values_of_lossy("record types") {
        record_types
            .iter()
            .map(|rt| RecordType::from_str(&rt.to_uppercase()).unwrap())
            .collect()
    } else {
        DEFAULT_RECORD_TYPES
            .iter()
            .map(|rt| RecordType::from_str(&rt.to_uppercase()).unwrap())
            .collect()
    };

    Ok(record_types)
}

// Newtype pattern for Display implementation
struct DnsResponse<'a>(pub &'a mhost::DnsResponse);

// Display impl for plain, basic output
impl<'a> fmt::Display for DnsResponse<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let DnsResponse(dns_response) = *self;
        if dns_response.answers.is_empty() {
            return write!(f, "DNS server {} has no records.", dns_response.server);
        }
        let _ = write!(f, "DNS server {} responded with\n", dns_response.server);
        let mut answers: Vec<String> = dns_response
            .answers
            .iter()
            .map(|answer| match *answer.rdata() {
                RData::A(ip) => format!(" * IPv4: {}", ip),
                RData::AAAA(ip) => format!(" * IPv6: {}", ip),
                RData::CNAME(ref name) => format!(" * CNAME: {}", name),
                RData::MX(ref mx) => {
                    format!(
                        " * MX: {} with preference {}",
                        mx.exchange(),
                        mx.preference()
                    )
                }
                RData::NS(ref name) => format!(" * NS: {}", name),
                RData::SOA(ref soa) => {
                    format!(
                        " * SOA: {} {} {} {} {} {} {}",
                        soa.mname(),
                        soa.rname(),
                        soa.serial(),
                        soa.refresh(),
                        soa.retry(),
                        soa.expire(),
                        soa.minimum()
                    )
                }
                RData::TXT(ref txt) => format!(" * TXT: {}", txt.txt_data().join(" ")),
                RData::PTR(ref ptr) => format!(" * PTR: {}", ptr.to_string()),
                ref x => format!(" * unclassified answer: {:?}", x),
            })
            .collect();
        answers.sort();
        write!(f, "{}", answers.join("\n"))
    }
}

error_chain! {
    errors {
        CliArgsParsingError {
            description("failed to parse CLI arguments")
            display("failed to parse CLI arguments")
        }

        ResolvConfError {
            description("failed to parse /etc/resolv.conf")
            display("failed to parse /etc/resolv.cons")
        }

        ServerIpAddrParsingError {
            description("failed to parse server IP address")
            display("failed to parse server IP address")
        }

        ResoureRecordTypeParsingError {
            description("failed to parse resource record type")
            display("failed to parse resource record type")
        }
    }
}

quick_main!(run);
<commit_msg>Improve error reporting<commit_after>#[macro_use]
extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate mhost;
extern crate resolv_conf;
extern crate tokio_core;
extern crate trust_dns;

use mhost::{multiple_lookup, DnsQuery};

use clap::{App, Arg, ArgMatches, Shell};
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::net::IpAddr;
use std::str::FromStr;
use std::time::Duration;
use tokio_core::reactor::Core;
use trust_dns::rr::{RData, RecordType};

// Arbitrary list of public DNS servers
static DEFAULT_DNS_SERVERS: &'static [&str] = &[
    // "Level3",
    "209.244.0.3",
    "209.244.0.4",
    // "Verisign",
    "64.6.64.6",
    "64.6.65.6",
    // "Google",
    "8.8.8.8",
    "8.8.4.4",
    // "DNS.WATCH",
    "84.200.69.80",
    "84.200.70.40",
    // "OpenDNS Home",
    "208.67.222.222",
    "208.67.220.220",
    // "SafeDNS",
    "195.46.39.39",
    "195.46.39.40",
    // "Dyn",
    "216.146.35.35",
    "216.146.36.36",
    // "FreeDNS",
    "37.235.1.174",
    "37.235.1.177",
    // "Alternate DNS",
    "198.101.242.72",
    "23.253.163.53",
];

static DEFAULT_RECORD_TYPES: &'static [&str] = &["a", "aaaa", "mx"];

fn run() -> Result<()> {
    let args = build_cli().get_matches();

    if args.is_present("completions") {
        return generate_completion(&args);
    }

    let dns_endpoints = get_dns_servers(&args)
        .chain_err(|| ErrorKind::ServerIpAddrParsingError)?
        .into_iter()
        .map(|s| (s, 53))
        .collect();

    let timeout = value_t!(args, "timeout", u64)
        .map(Duration::from_secs)
        .unwrap();

    let mut query = match IpAddr::from_str(args.value_of("domain name").unwrap()) {
        Ok(ip) => DnsQuery::from(ip, vec![RecordType::PTR]),
        Err(_) => {
            let record_types = get_record_types(&args).chain_err(|| {
                ErrorKind::ResoureRecordTypeParsingError
            })?;
            DnsQuery::new(args.value_of("domain name").unwrap(), record_types)
        }
    };
    query = query.set_timeout(timeout);

    let mut io_loop = Core::new().unwrap();
    let lookup = multiple_lookup(&io_loop.handle(), query, dns_endpoints);
    let result = io_loop.run(lookup);

    match result {
        Ok(ref responses) => {
            for response in responses {
                match *response {
                    Ok(ref x) => println!("{}", DnsResponse(x)),
                    Err(ref e) => print_error(e),
                }
            }
        }
        Err(_) => {
            println!("General Error");
        }
    }

    Ok(())
}

fn build_cli() -> App<'static, 'static> {
    let name = env!("CARGO_PKG_NAME");
    let version = env!("CARGO_PKG_VERSION");
    let about = env!("CARGO_PKG_DESCRIPTION");

    App::new(name)
        .version(version)
        .about(about)
        .arg(
            Arg::with_name("domain name")
                .index(1)
                .required(true)
                .conflicts_with("completions")
                .help("domain name or IP address to look up"),
        )
        .arg(
            Arg::with_name("timeout")
                .long("timeout")
                .default_value("5")
                .help("timeout for server responses in sec")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("record types")
                .long("type")
                .short("t")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1)
                .possible_values(
                    &[
                        "a",
                        "aaaa",
                        "any",
                        "cname",
                        "dnskey",
                        "mx",
                        "ns",
                        "opt",
                        "ptr",
                        "soa",
                        "srv",
                        "txt",
                    ],
                )
                .help("Select resource record type [default: a, aaaa, mx]"),
        )
        .arg(
            Arg::with_name("dont use local dns servers")
                .short("L")
                .help("Do not use local (/etc/resolv.conf) DNS servers"),
        )
        .arg(Arg::with_name("predefined server").short("S").help(
            "use predefined DNS server set",
        ))
        .arg(
            Arg::with_name("DNS servers")
                .long("server")
                .short("s")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1)
                .help(
                    "DNS servers to use; if empty use predefined, public DNS server",
                ),
        )
        .arg(
            Arg::with_name("completions")
                .long("completions")
                .takes_value(true)
                .hidden(true)
                .possible_values(&["bash", "fish", "zsh"])
                .help("The shell to generate the script for"),
        )
}

fn generate_completion(args: &ArgMatches) -> Result<()> {
    let bin_name = env!("CARGO_PKG_NAME");
    let shell = args.value_of("completions").ok_or(
        ErrorKind::CliArgsParsingError,
    )?;
    build_cli().gen_completions_to(
        bin_name,
        shell.parse::<Shell>().unwrap(),
        &mut std::io::stdout(),
    );
    Ok(())
}

fn get_local_dns_servers() -> Result<Vec<IpAddr>> {
    let mut buf = Vec::with_capacity(4096);
    let mut f = File::open("/etc/resolv.conf").chain_err(
        || ErrorKind::ResolvConfError,
    )?;
    f.read_to_end(&mut buf).unwrap();
    let cfg = resolv_conf::Config::parse(&buf[..]).chain_err(|| {
        ErrorKind::ResolvConfError
    })?;
    Ok(cfg.nameservers)
}

fn get_dns_servers(args: &ArgMatches) -> Result<Vec<IpAddr>> {
    let mut dns_servers: Vec<IpAddr> = Vec::new();
    if let Some(servers) = args.values_of_lossy("DNS servers") {
        dns_servers.extend(servers.into_iter().map(|server| {
            IpAddr::from_str(&server).unwrap()
        }));
    }
    if args.is_present("predefined server") {
        dns_servers.extend(DEFAULT_DNS_SERVERS.iter().map(|server| {
            IpAddr::from_str(server).unwrap()
        }));
    }
    if !args.is_present("dont use local dns servers") {
        dns_servers.extend(get_local_dns_servers()?);
    }

    Ok(dns_servers)
}

fn get_record_types(args: &ArgMatches) -> Result<Vec<RecordType>> {
    let record_types = if let Some(record_types) = args.values_of_lossy("record types") {
        record_types
            .iter()
            .map(|rt| RecordType::from_str(&rt.to_uppercase()).unwrap())
            .collect()
    } else {
        DEFAULT_RECORD_TYPES
            .iter()
            .map(|rt| RecordType::from_str(&rt.to_uppercase()).unwrap())
            .collect()
    };

    Ok(record_types)
}

// Newtype pattern for Display implementation
struct DnsResponse<'a>(pub &'a mhost::DnsResponse);

// Display impl for plain, basic output
impl<'a> fmt::Display for DnsResponse<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let DnsResponse(dns_response) = *self;
        if dns_response.answers.is_empty() {
            return write!(f, "DNS server {} has no records.", dns_response.server);
        }
        let _ = write!(f, "DNS server {} responded with\n", dns_response.server);
        let mut answers: Vec<String> = dns_response
            .answers
            .iter()
            .map(|answer| match *answer.rdata() {
                RData::A(ip) => format!(" * IPv4: {}", ip),
                RData::AAAA(ip) => format!(" * IPv6: {}", ip),
                RData::CNAME(ref name) => format!(" * CNAME: {}", name),
                RData::MX(ref mx) => {
                    format!(
                        " * MX: {} with preference {}",
                        mx.exchange(),
                        mx.preference()
                    )
                }
                RData::NS(ref name) => format!(" * NS: {}", name),
                RData::SOA(ref soa) => {
                    format!(
                        " * SOA: {} {} {} {} {} {} {}",
                        soa.mname(),
                        soa.rname(),
                        soa.serial(),
                        soa.refresh(),
                        soa.retry(),
                        soa.expire(),
                        soa.minimum()
                    )
                }
                RData::TXT(ref txt) => format!(" * TXT: {}", txt.txt_data().join(" ")),
                RData::PTR(ref ptr) => format!(" * PTR: {}", ptr.to_string()),
                ref x => format!(" * unclassified answer: {:?}", x),
            })
            .collect();
        answers.sort();
        write!(f, "{}", answers.join("\n"))
    }
}

fn print_error(err: &mhost::Error) {
    print!("{} ", err);
    for e in err.iter().skip(1) {
        print!("because {}", e);
    }
    println!();

    // The backtrace is only available if run with `RUST_BACKTRACE=1`.
    if let Some(backtrace) = err.backtrace() {
        println!("backtrace: {:?}", backtrace);
    }
}

error_chain! {
    errors {
        CliArgsParsingError {
            description("failed to parse CLI arguments")
            display("failed to parse CLI arguments")
        }

        ResolvConfError {
            description("failed to parse /etc/resolv.conf")
            display("failed to parse /etc/resolv.cons")
        }

        ServerIpAddrParsingError {
            description("failed to parse server IP address")
            display("failed to parse server IP address")
        }

        ResoureRecordTypeParsingError {
            description("failed to parse resource record type")
            display("failed to parse resource record type")
        }
    }
}

quick_main!(run);
<|endoftext|>


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

struct PrinterActor {
    callbacks: VecDeque<String>,
}

impl PrinterActor {
    fn new() -> PrinterActor {
        PrinterActor {
            callbacks: VecDeque::new(),
        }
    }

    fn send(&mut self, message: String) {
        self.callbacks.push_back(message);
    }

    fn treat_messages(&mut self) {
        if let Some(s) = self.callbacks.pop_front() {
            println!("{}", s);
        }
    }
}

fn main() {
    let mut actor = PrinterActor::new();

    actor.send("Hello world!".to_string());

    actor.treat_messages();
}
<commit_msg>WIP - Add Actor Trait and worker queue.<commit_after>use std::cell::RefCell;
use std::collections::VecDeque;
use std::sync::Arc;

trait Actor {
    fn treat_messages(&mut self);
}

struct PrinterActor {
    // VecDeque is the current recommendation for FIFOs.
    callbacks: VecDeque<String>,
    // TODO(gamazeps): Find the proper type for the main queue.
    worker_queue: Arc<RefCell<VecDeque<PrinterActor>>>,
}

impl Actor for PrinterActor {
    fn treat_messages(&mut self) {
        if let Some(s) = self.callbacks.pop_front() {
            println!("{}", s);
        }
    }
}

impl PrinterActor {
    fn new(queue: Arc<RefCell<VecDeque<PrinterActor>>>) -> PrinterActor {
        PrinterActor {
            callbacks: VecDeque::new(),
            worker_queue: queue,
        }
    }

    fn send(&mut self, message: String) {
        self.callbacks.push_back(message);
    }
}

fn main() {
    // Arc allows managing a shared ressource in a thread safe way.
    // RefCell allows sharing a mutable reference.
    let shared_queue: Arc<RefCell<VecDeque<PrinterActor>>> = Arc::new(RefCell::new(VecDeque::new()));
    let mut actor = PrinterActor::new(shared_queue.clone());

    actor.send("Hello world!".to_string());

    actor.treat_messages();
}
<|endoftext|>


<commit_before>/// The sure stream.
///
/// The sure stream represents a linearization of a SureTree.  By keeping
/// representations as iterators across SureNodes instead of keeping an
/// entire tree in memory, we can process larger filesystem trees, using
/// temporary space on the hard disk instead of using memory.
use crate::{suretree::AttMap, Error, Result};
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
use std::{
    fs::File,
    io::{self, BufRead, BufReader, BufWriter, Read, Write},
    path::{Path, PathBuf},
};
use weave::NamingConvention;

mod compare;
pub mod fs;
mod fullpath;
mod hashes;

pub use compare::compare_trees;
pub use fullpath::into_tracker;
pub use hashes::{HashCombiner, HashUpdater, Source};

#[derive(Clone, Debug)]
pub enum SureNode {
    Enter { name: String, atts: AttMap },
    Leave,
    File { name: String, atts: AttMap },
    Sep,
}

impl SureNode {
    pub fn is_enter(&self) -> bool {
        matches!(self, SureNode::Enter { .. })
    }

    pub fn is_reg_file(&self) -> bool {
        match self {
            SureNode::File { atts, .. } => atts["kind"] == "file",
            _ => false,
        }
    }

    pub fn is_file(&self) -> bool {
        matches!(self, SureNode::File { .. })
    }

    pub fn is_leave(&self) -> bool {
        matches!(self, SureNode::Leave)
    }

    pub fn is_sep(&self) -> bool {
        matches!(self, SureNode::Sep)
    }

    pub fn needs_hash(&self) -> bool {
        match self {
            SureNode::File { atts, .. } => atts["kind"] == "file" && !atts.contains_key("sha1"),
            _ => false,
        }
    }

    pub fn size(&self) -> u64 {
        match self {
            SureNode::File { atts, .. } => {
                atts.get("size").map(|x| x.parse().unwrap()).unwrap_or(0)
            }
            _ => 0,
        }
    }

    /// Get the name of this node.  Panics if the node type does not have
    /// an associated name.
    pub fn name(&self) -> &str {
        match self {
            SureNode::File { ref name, .. } => name,
            SureNode::Enter { ref name, .. } => name,
            _ => panic!("Node does not have a name"),
        }
    }

    /// Safely get the name of this node.
    pub fn get_name(&self) -> Option<&str> {
        match self {
            SureNode::File { ref name, .. } => Some(name),
            SureNode::Enter { ref name, .. } => Some(name),
            _ => None,
        }
    }

    /// Get a nice representation of the kind of this node.  Returns "???"
    /// if the kind isn't meaningful.
    pub fn kind(&self) -> &str {
        self.atts()
            .map(|a| a.get("kind").map(|k| &k[..]).unwrap_or("???"))
            .unwrap_or("???")
    }

    /// Access the nodes attributes.
    pub fn atts(&self) -> Option<&AttMap> {
        match self {
            SureNode::File { ref atts, .. } => Some(atts),
            SureNode::Enter { ref atts, .. } => Some(atts),
            _ => None,
        }
    }

    /// Access the nodes attributes mutably.
    pub fn atts_mut(&mut self) -> Option<&mut AttMap> {
        match self {
            SureNode::File { ref mut atts, .. } => Some(atts),
            SureNode::Enter { ref mut atts, .. } => Some(atts),
            _ => None,
        }
    }
}

// TODO: These might be possible to make more generic, but it gets messy,
// as it might just be best to assume failure.

/// Write a sure iterator to a standard gzipped file of the given name.
pub fn save<P, I>(name: P, nodes: I) -> Result<()>
where
    P: AsRef<Path>,
    I: Iterator<Item = Result<SureNode>>,
{
    let wr = File::create(name)?;
    let wr = GzEncoder::new(wr, Compression::default());
    save_to(wr, nodes)
}

/// Write a sure iterator to a new temp file with a given naming
/// convention.  Returns the name of the file, if it could be created.  The
/// data will not be written compressed.
pub fn save_naming<I, N>(naming: &N, nodes: I) -> Result<PathBuf>
where
    N: NamingConvention,
    I: Iterator<Item = Result<SureNode>>,
{
    let (tmp_name, mut tmp_file) = naming.temp_file()?;
    save_to(&mut tmp_file, nodes)?;
    Ok(tmp_name)
}

/// Save a sure tree to the given writer.
pub fn save_to<W, I>(wr: W, nodes: I) -> Result<()>
where
    W: Write,
    I: Iterator<Item = Result<SureNode>>,
{
    let mut wr = BufWriter::new(wr);

    writeln!(&mut wr, "asure-2.0")?;
    writeln!(&mut wr, "-----")?;

    for node in nodes {
        match node? {
            SureNode::Enter { name, atts } => header(&mut wr, 'd', &name, &atts)?,
            SureNode::File { name, atts } => header(&mut wr, 'f', &name, &atts)?,
            SureNode::Sep => writeln!(&mut wr, "-")?,
            SureNode::Leave => writeln!(&mut wr, "u")?,
        }
    }
    Ok(())
}

/// For pushed based writing, we can also write using a NodeWriter.
pub struct NodeWriter<W: Write> {
    writer: BufWriter<W>,
}

impl<W: Write> NodeWriter<W> {
    pub fn new(writer: W) -> Result<NodeWriter<W>> {
        let mut wr = BufWriter::new(writer);
        writeln!(&mut wr, "asure-2.0")?;
        writeln!(&mut wr, "-----")?;

        Ok(NodeWriter { writer: wr })
    }

    pub fn write_node(&mut self, node: &SureNode) -> Result<()> {
        match node {
            SureNode::Enter { name, atts } => header(&mut self.writer, 'd', &name, &atts)?,
            SureNode::File { name, atts } => header(&mut self.writer, 'f', &name, &atts)?,
            SureNode::Sep => writeln!(&mut self.writer, "-")?,
            SureNode::Leave => writeln!(&mut self.writer, "u")?,
        }
        Ok(())
    }
}

fn header<W: Write>(out: &mut W, kind: char, name: &str, atts: &AttMap) -> Result<()> {
    write!(out, "{}{} [", kind, name)?;

    for (k, v) in atts {
        write!(out, "{} {} ", k, v)?;
    }
    writeln!(out, "]")?;
    Ok(())
}

/// Load and iterate a sure tree from a standard gzip compressed surefile.
pub fn load<P: AsRef<Path>>(name: P) -> Result<ReadIterator<GzDecoder<File>>> {
    let rd = File::open(name)?;
    let rd = GzDecoder::new(rd);
    load_from(rd)
}

/// Load a surenode sequence from the given reader.
pub fn load_from<R: Read>(rd: R) -> Result<ReadIterator<R>> {
    let rd = BufReader::new(rd);
    let mut lines = rd.split(b'\n');

    fixed(&mut lines, b"asure-2.0")?;
    fixed(&mut lines, b"-----")?;

    Ok(ReadIterator {
        lines,
        depth: 0,
        done: false,
    })
}

fn fixed<I>(inp: &mut I, exp: &[u8]) -> Result<()>
where
    I: Iterator<Item = io::Result<Vec<u8>>>,
{
    match inp.next() {
        Some(Ok(ref text)) if &text[..] == exp => Ok(()),
        Some(Ok(ref text)) => Err(Error::UnexpectedLine(
            String::from_utf8_lossy(text).into_owned(),
            String::from_utf8_lossy(exp).into_owned(),
        )),
        Some(Err(e)) => Err(Error::SureFileError(e)),
        None => Err(Error::SureFileEof),
    }
}

pub struct ReadIterator<R> {
    lines: io::Split<BufReader<R>>,
    depth: usize,
    done: bool,
}

impl<R: Read> Iterator for ReadIterator<R> {
    type Item = Result<SureNode>;

    fn next(&mut self) -> Option<Result<SureNode>> {
        if self.done {
            return None;
        }

        let line = match self.get_line() {
            Ok(line) => line,
            Err(e) => return Some(Err(e)),
        };

        match line[0] {
            b'd' => {
                let (dname, datts) = decode_entity(&line[1..]);
                self.depth += 1;
                Some(Ok(SureNode::Enter {
                    name: dname,
                    atts: datts,
                }))
            }
            b'f' => {
                let (fname, fatts) = decode_entity(&line[1..]);
                Some(Ok(SureNode::File {
                    name: fname,
                    atts: fatts,
                }))
            }
            b'-' => Some(Ok(SureNode::Sep)),
            b'u' => {
                self.depth -= 1;
                if self.depth == 0 {
                    self.done = true;
                }
                Some(Ok(SureNode::Leave))
            }
            ch => Some(Err(Error::InvalidSurefileChar(ch as char))),
        }
    }
}

impl<R: Read> ReadIterator<R> {
    fn get_line(&mut self) -> Result<Vec<u8>> {
        match self.lines.next() {
            None => Err(Error::TruncatedSurefile),
            Some(l) => Ok(l?),
        }
    }
}

// TODO: This should return Result to handle errors.
pub(crate) fn decode_entity(text: &[u8]) -> (String, AttMap) {
    let (name, mut text) = get_delim(text, b' ');
    assert!(text[0] == b'[');
    text = &text[1..];

    let mut atts = AttMap::new();
    while text[0] != b']' {
        let (key, t2) = get_delim(text, b' ');
        let (value, t2) = get_delim(t2, b' ');
        text = t2;

        atts.insert(key, value);
    }

    (name, atts)
}

fn get_delim(text: &[u8], delim: u8) -> (String, &[u8]) {
    let mut it = text.iter();
    let space = it.position(|&s| s == delim).unwrap();
    (
        String::from_utf8(text[..space].to_owned()).unwrap(),
        &text[space + 1..],
    )
}
<commit_msg>Fix a doc comment<commit_after>//! The sure stream.
//!
//! The sure stream represents a linearization of a SureTree.  By keeping
//! representations as iterators across SureNodes instead of keeping an
//! entire tree in memory, we can process larger filesystem trees, using
//! temporary space on the hard disk instead of using memory.
use crate::{suretree::AttMap, Error, Result};
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
use std::{
    fs::File,
    io::{self, BufRead, BufReader, BufWriter, Read, Write},
    path::{Path, PathBuf},
};
use weave::NamingConvention;

mod compare;
pub mod fs;
mod fullpath;
mod hashes;

pub use compare::compare_trees;
pub use fullpath::into_tracker;
pub use hashes::{HashCombiner, HashUpdater, Source};

#[derive(Clone, Debug)]
pub enum SureNode {
    Enter { name: String, atts: AttMap },
    Leave,
    File { name: String, atts: AttMap },
    Sep,
}

impl SureNode {
    pub fn is_enter(&self) -> bool {
        matches!(self, SureNode::Enter { .. })
    }

    pub fn is_reg_file(&self) -> bool {
        match self {
            SureNode::File { atts, .. } => atts["kind"] == "file",
            _ => false,
        }
    }

    pub fn is_file(&self) -> bool {
        matches!(self, SureNode::File { .. })
    }

    pub fn is_leave(&self) -> bool {
        matches!(self, SureNode::Leave)
    }

    pub fn is_sep(&self) -> bool {
        matches!(self, SureNode::Sep)
    }

    pub fn needs_hash(&self) -> bool {
        match self {
            SureNode::File { atts, .. } => atts["kind"] == "file" && !atts.contains_key("sha1"),
            _ => false,
        }
    }

    pub fn size(&self) -> u64 {
        match self {
            SureNode::File { atts, .. } => {
                atts.get("size").map(|x| x.parse().unwrap()).unwrap_or(0)
            }
            _ => 0,
        }
    }

    /// Get the name of this node.  Panics if the node type does not have
    /// an associated name.
    pub fn name(&self) -> &str {
        match self {
            SureNode::File { ref name, .. } => name,
            SureNode::Enter { ref name, .. } => name,
            _ => panic!("Node does not have a name"),
        }
    }

    /// Safely get the name of this node.
    pub fn get_name(&self) -> Option<&str> {
        match self {
            SureNode::File { ref name, .. } => Some(name),
            SureNode::Enter { ref name, .. } => Some(name),
            _ => None,
        }
    }

    /// Get a nice representation of the kind of this node.  Returns "???"
    /// if the kind isn't meaningful.
    pub fn kind(&self) -> &str {
        self.atts()
            .map(|a| a.get("kind").map(|k| &k[..]).unwrap_or("???"))
            .unwrap_or("???")
    }

    /// Access the nodes attributes.
    pub fn atts(&self) -> Option<&AttMap> {
        match self {
            SureNode::File { ref atts, .. } => Some(atts),
            SureNode::Enter { ref atts, .. } => Some(atts),
            _ => None,
        }
    }

    /// Access the nodes attributes mutably.
    pub fn atts_mut(&mut self) -> Option<&mut AttMap> {
        match self {
            SureNode::File { ref mut atts, .. } => Some(atts),
            SureNode::Enter { ref mut atts, .. } => Some(atts),
            _ => None,
        }
    }
}

// TODO: These might be possible to make more generic, but it gets messy,
// as it might just be best to assume failure.

/// Write a sure iterator to a standard gzipped file of the given name.
pub fn save<P, I>(name: P, nodes: I) -> Result<()>
where
    P: AsRef<Path>,
    I: Iterator<Item = Result<SureNode>>,
{
    let wr = File::create(name)?;
    let wr = GzEncoder::new(wr, Compression::default());
    save_to(wr, nodes)
}

/// Write a sure iterator to a new temp file with a given naming
/// convention.  Returns the name of the file, if it could be created.  The
/// data will not be written compressed.
pub fn save_naming<I, N>(naming: &N, nodes: I) -> Result<PathBuf>
where
    N: NamingConvention,
    I: Iterator<Item = Result<SureNode>>,
{
    let (tmp_name, mut tmp_file) = naming.temp_file()?;
    save_to(&mut tmp_file, nodes)?;
    Ok(tmp_name)
}

/// Save a sure tree to the given writer.
pub fn save_to<W, I>(wr: W, nodes: I) -> Result<()>
where
    W: Write,
    I: Iterator<Item = Result<SureNode>>,
{
    let mut wr = BufWriter::new(wr);

    writeln!(&mut wr, "asure-2.0")?;
    writeln!(&mut wr, "-----")?;

    for node in nodes {
        match node? {
            SureNode::Enter { name, atts } => header(&mut wr, 'd', &name, &atts)?,
            SureNode::File { name, atts } => header(&mut wr, 'f', &name, &atts)?,
            SureNode::Sep => writeln!(&mut wr, "-")?,
            SureNode::Leave => writeln!(&mut wr, "u")?,
        }
    }
    Ok(())
}

/// For pushed based writing, we can also write using a NodeWriter.
pub struct NodeWriter<W: Write> {
    writer: BufWriter<W>,
}

impl<W: Write> NodeWriter<W> {
    pub fn new(writer: W) -> Result<NodeWriter<W>> {
        let mut wr = BufWriter::new(writer);
        writeln!(&mut wr, "asure-2.0")?;
        writeln!(&mut wr, "-----")?;

        Ok(NodeWriter { writer: wr })
    }

    pub fn write_node(&mut self, node: &SureNode) -> Result<()> {
        match node {
            SureNode::Enter { name, atts } => header(&mut self.writer, 'd', &name, &atts)?,
            SureNode::File { name, atts } => header(&mut self.writer, 'f', &name, &atts)?,
            SureNode::Sep => writeln!(&mut self.writer, "-")?,
            SureNode::Leave => writeln!(&mut self.writer, "u")?,
        }
        Ok(())
    }
}

fn header<W: Write>(out: &mut W, kind: char, name: &str, atts: &AttMap) -> Result<()> {
    write!(out, "{}{} [", kind, name)?;

    for (k, v) in atts {
        write!(out, "{} {} ", k, v)?;
    }
    writeln!(out, "]")?;
    Ok(())
}

/// Load and iterate a sure tree from a standard gzip compressed surefile.
pub fn load<P: AsRef<Path>>(name: P) -> Result<ReadIterator<GzDecoder<File>>> {
    let rd = File::open(name)?;
    let rd = GzDecoder::new(rd);
    load_from(rd)
}

/// Load a surenode sequence from the given reader.
pub fn load_from<R: Read>(rd: R) -> Result<ReadIterator<R>> {
    let rd = BufReader::new(rd);
    let mut lines = rd.split(b'\n');

    fixed(&mut lines, b"asure-2.0")?;
    fixed(&mut lines, b"-----")?;

    Ok(ReadIterator {
        lines,
        depth: 0,
        done: false,
    })
}

fn fixed<I>(inp: &mut I, exp: &[u8]) -> Result<()>
where
    I: Iterator<Item = io::Result<Vec<u8>>>,
{
    match inp.next() {
        Some(Ok(ref text)) if &text[..] == exp => Ok(()),
        Some(Ok(ref text)) => Err(Error::UnexpectedLine(
            String::from_utf8_lossy(text).into_owned(),
            String::from_utf8_lossy(exp).into_owned(),
        )),
        Some(Err(e)) => Err(Error::SureFileError(e)),
        None => Err(Error::SureFileEof),
    }
}

pub struct ReadIterator<R> {
    lines: io::Split<BufReader<R>>,
    depth: usize,
    done: bool,
}

impl<R: Read> Iterator for ReadIterator<R> {
    type Item = Result<SureNode>;

    fn next(&mut self) -> Option<Result<SureNode>> {
        if self.done {
            return None;
        }

        let line = match self.get_line() {
            Ok(line) => line,
            Err(e) => return Some(Err(e)),
        };

        match line[0] {
            b'd' => {
                let (dname, datts) = decode_entity(&line[1..]);
                self.depth += 1;
                Some(Ok(SureNode::Enter {
                    name: dname,
                    atts: datts,
                }))
            }
            b'f' => {
                let (fname, fatts) = decode_entity(&line[1..]);
                Some(Ok(SureNode::File {
                    name: fname,
                    atts: fatts,
                }))
            }
            b'-' => Some(Ok(SureNode::Sep)),
            b'u' => {
                self.depth -= 1;
                if self.depth == 0 {
                    self.done = true;
                }
                Some(Ok(SureNode::Leave))
            }
            ch => Some(Err(Error::InvalidSurefileChar(ch as char))),
        }
    }
}

impl<R: Read> ReadIterator<R> {
    fn get_line(&mut self) -> Result<Vec<u8>> {
        match self.lines.next() {
            None => Err(Error::TruncatedSurefile),
            Some(l) => Ok(l?),
        }
    }
}

// TODO: This should return Result to handle errors.
pub(crate) fn decode_entity(text: &[u8]) -> (String, AttMap) {
    let (name, mut text) = get_delim(text, b' ');
    assert!(text[0] == b'[');
    text = &text[1..];

    let mut atts = AttMap::new();
    while text[0] != b']' {
        let (key, t2) = get_delim(text, b' ');
        let (value, t2) = get_delim(t2, b' ');
        text = t2;

        atts.insert(key, value);
    }

    (name, atts)
}

fn get_delim(text: &[u8], delim: u8) -> (String, &[u8]) {
    let mut it = text.iter();
    let space = it.position(|&s| s == delim).unwrap();
    (
        String::from_utf8(text[..space].to_owned()).unwrap(),
        &text[space + 1..],
    )
}
<|endoftext|>


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

use std::collections::{RingBuf, Deque};

/// A polygon with 4 points. Maps to `GL_QUADS`
#[deriving(Clone, Show, PartialEq, Eq)]
pub struct Quad<T> {
    pub x: T,
    pub y: T,
    pub z: T,
    pub w: T
}

impl<T> Quad<T> {
    /// create a new `Quad` with supplied vertices
    pub fn new(v0: T, v1: T, v2: T, v3: T) -> Quad<T> {
        Quad {
            x: v0,
            y: v1,
            z: v2,
            w: v3
        }
    }
}

/// A polygon with 3 points. Maps to `GL_TRIANGLE`
#[deriving(Clone, Show, PartialEq, Eq)]
pub struct Triangle<T> {
    pub x: T,
    pub y: T,
    pub z: T
}

impl<T> Triangle<T> {
    /// create a new `Triangle` with supplied vertcies
    pub fn new(v0: T, v1: T, v2: T) -> Triangle<T> {
        Triangle {
            x: v0,
            y: v1,
            z: v2
        }
    }
}

/// This is All-the-types container. This exists since some generators
/// produce both `Triangles` and `Quads`.
#[deriving(Show, Clone, PartialEq)]
pub enum Polygon<T> {
    PolyTri(Triangle<T>),
    PolyQuad(Quad<T>)
}

/// The core mechanism of `Vertices` trait. This is a mechanism for unwraping
/// a polygon extracting all of the vertices that it bound together.
pub trait EmitVertices<T> {
    /// Consume a polygon, each
    /// vertex is emitted to the parent function by calling the supplied
    /// lambda function
    fn emit_vertices(self, emit: |T|);
}

impl<T> EmitVertices<T> for Triangle<T> {
    fn emit_vertices(self, emit: |T|) {
        let Triangle{x: x, y: y, z: z} = self;
        emit(x);
        emit(y);
        emit(z);
    }
}

impl<T> EmitVertices<T> for Quad<T> {
    fn emit_vertices(self, emit: |T|) {
        let Quad{x: x, y: y, z: z, w: w} = self;
        emit(x);
        emit(y);
        emit(z);
        emit(w);
    }
}

impl<T> EmitVertices<T> for Polygon<T> {
    fn emit_vertices(self, emit: |T|) {
        match self {
            PolyTri(p) => p.emit_vertices(emit),
            PolyQuad(p) => p.emit_vertices(emit)
        }
    }
}

/// Supplies a way to convert an iterator of polygons to an iterator
/// of vertices. Useful for when you need to write the vertices into
/// a graphics pipeline.
pub trait Vertices<SRC, V> {
    /// Convert a polygon iterator to a vertices iterator.
    fn vertices(self) -> VerticesIterator<SRC, V>;
}

impl<V, P: EmitVertices<V>, T: Iterator<P>> Vertices<T, V> for T {
    fn vertices(self) -> VerticesIterator<T, V> {
        VerticesIterator {
            source: self,
            buffer: RingBuf::new()
        }
    }
}

pub struct VerticesIterator<SRC, V> {
    source: SRC,
    buffer: RingBuf<V>
}

impl<V, U: EmitVertices<V>, SRC: Iterator<U>> Iterator<V> for VerticesIterator<SRC, V> {
    fn next(&mut self) -> Option<V> {
        loop {
            match self.buffer.pop_front() {
                Some(v) => return Some(v),
                None => ()
            }

            match self.source.next() {
                Some(p) => p.emit_vertices(|v| self.buffer.push(v)),
                None => return None
            }
        }
    }
}

// equivalent of `map` but per-vertex
pub trait MapVertex<T, U, P> {
    /// map a function to each vertex in polygon creating a new polygon
    fn map_vertex(self, f: |T| -> U) -> P;
}

impl<T: Clone, U> MapVertex<T, U, Triangle<U>> for Triangle<T> {
    fn map_vertex(self, map: |T| -> U) -> Triangle<U> {
        let Triangle{x: x, y: y, z: z} = self;
        Triangle {
            x: map(x),
            y: map(y),
            z: map(z)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U, Quad<U>> for Quad<T> {
    fn map_vertex(self, map: |T| -> U) -> Quad<U> {
        let Quad{x: x, y: y, z: z, w: w} = self;
        Quad {
            x: map(x),
            y: map(y),
            z: map(z),
            w: map(w)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U, Polygon<U>> for Polygon<T> {
    fn map_vertex(self, map: |T| -> U) -> Polygon<U> {
        match self {
            PolyTri(p) => PolyTri(p.map_vertex(map)),
            PolyQuad(p) => PolyQuad(p.map_vertex(map))
        }
    }
}

/// This acts very similar to a vertex shader. It gives a way to manipulate
/// and modify the vertices in a polygon. This is useful if you need to scale
/// the mesh using a matrix multiply, or just for modifying the type of each
/// vertex.
pub trait MapToVertices<T, U> {
    /// from a iterator of polygons, produces a iterator of polygons. Each
    /// vertex in the process is modified with the suppled function.
    fn vertex<'a>(self, map: |T|:'a -> U) -> MapToVerticesIter<'a, Self, T, U>;
}

impl<V_IN, V_OUT, P, P_IN: MapVertex<V_IN, V_OUT, P>, T: Iterator<P_IN>>
    MapToVertices<V_IN, V_OUT> for T {
    fn vertex<'a>(self, map: |V_IN|:'a -> V_OUT) -> MapToVerticesIter<'a, T, V_IN, V_OUT> {
        MapToVerticesIter {
            src: self,
            f: map
        }
    }
}

struct MapToVerticesIter<'a, SRC, T, U> {
    src: SRC,
    f: |T|:'a -> U
}

impl<'a, P_IN: MapVertex<T, U, P>,
         SRC: Iterator<P_IN>, T, U, P> Iterator<P> for MapToVerticesIter<'a, SRC, T, U> {
    fn next(&mut self) -> Option<P> {
        self.src.next().map(|x| x.map_vertex(|x| (self.f)(x)))
    }
}<commit_msg>fixed warnings from naming in poly.rs<commit_after>//   Copyright Colin Sherratt 2014
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

use std::collections::{RingBuf, Deque};

/// A polygon with 4 points. Maps to `GL_QUADS`
#[deriving(Clone, Show, PartialEq, Eq)]
pub struct Quad<T> {
    pub x: T,
    pub y: T,
    pub z: T,
    pub w: T
}

impl<T> Quad<T> {
    /// create a new `Quad` with supplied vertices
    pub fn new(v0: T, v1: T, v2: T, v3: T) -> Quad<T> {
        Quad {
            x: v0,
            y: v1,
            z: v2,
            w: v3
        }
    }
}

/// A polygon with 3 points. Maps to `GL_TRIANGLE`
#[deriving(Clone, Show, PartialEq, Eq)]
pub struct Triangle<T> {
    pub x: T,
    pub y: T,
    pub z: T
}

impl<T> Triangle<T> {
    /// create a new `Triangle` with supplied vertcies
    pub fn new(v0: T, v1: T, v2: T) -> Triangle<T> {
        Triangle {
            x: v0,
            y: v1,
            z: v2
        }
    }
}

/// This is All-the-types container. This exists since some generators
/// produce both `Triangles` and `Quads`.
#[deriving(Show, Clone, PartialEq)]
pub enum Polygon<T> {
    PolyTri(Triangle<T>),
    PolyQuad(Quad<T>)
}

/// The core mechanism of `Vertices` trait. This is a mechanism for unwraping
/// a polygon extracting all of the vertices that it bound together.
pub trait EmitVertices<T> {
    /// Consume a polygon, each
    /// vertex is emitted to the parent function by calling the supplied
    /// lambda function
    fn emit_vertices(self, emit: |T|);
}

impl<T> EmitVertices<T> for Triangle<T> {
    fn emit_vertices(self, emit: |T|) {
        let Triangle{x: x, y: y, z: z} = self;
        emit(x);
        emit(y);
        emit(z);
    }
}

impl<T> EmitVertices<T> for Quad<T> {
    fn emit_vertices(self, emit: |T|) {
        let Quad{x: x, y: y, z: z, w: w} = self;
        emit(x);
        emit(y);
        emit(z);
        emit(w);
    }
}

impl<T> EmitVertices<T> for Polygon<T> {
    fn emit_vertices(self, emit: |T|) {
        match self {
            PolyTri(p) => p.emit_vertices(emit),
            PolyQuad(p) => p.emit_vertices(emit)
        }
    }
}

/// Supplies a way to convert an iterator of polygons to an iterator
/// of vertices. Useful for when you need to write the vertices into
/// a graphics pipeline.
pub trait Vertices<SRC, V> {
    /// Convert a polygon iterator to a vertices iterator.
    fn vertices(self) -> VerticesIterator<SRC, V>;
}

impl<V, P: EmitVertices<V>, T: Iterator<P>> Vertices<T, V> for T {
    fn vertices(self) -> VerticesIterator<T, V> {
        VerticesIterator {
            source: self,
            buffer: RingBuf::new()
        }
    }
}

pub struct VerticesIterator<SRC, V> {
    source: SRC,
    buffer: RingBuf<V>
}

impl<V, U: EmitVertices<V>, SRC: Iterator<U>> Iterator<V> for VerticesIterator<SRC, V> {
    fn next(&mut self) -> Option<V> {
        loop {
            match self.buffer.pop_front() {
                Some(v) => return Some(v),
                None => ()
            }

            match self.source.next() {
                Some(p) => p.emit_vertices(|v| self.buffer.push(v)),
                None => return None
            }
        }
    }
}

// equivalent of `map` but per-vertex
pub trait MapVertex<T, U, P> {
    /// map a function to each vertex in polygon creating a new polygon
    fn map_vertex(self, f: |T| -> U) -> P;
}

impl<T: Clone, U> MapVertex<T, U, Triangle<U>> for Triangle<T> {
    fn map_vertex(self, map: |T| -> U) -> Triangle<U> {
        let Triangle{x: x, y: y, z: z} = self;
        Triangle {
            x: map(x),
            y: map(y),
            z: map(z)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U, Quad<U>> for Quad<T> {
    fn map_vertex(self, map: |T| -> U) -> Quad<U> {
        let Quad{x: x, y: y, z: z, w: w} = self;
        Quad {
            x: map(x),
            y: map(y),
            z: map(z),
            w: map(w)
        }
    }
}

impl<T: Clone, U> MapVertex<T, U, Polygon<U>> for Polygon<T> {
    fn map_vertex(self, map: |T| -> U) -> Polygon<U> {
        match self {
            PolyTri(p) => PolyTri(p.map_vertex(map)),
            PolyQuad(p) => PolyQuad(p.map_vertex(map))
        }
    }
}

/// This acts very similar to a vertex shader. It gives a way to manipulate
/// and modify the vertices in a polygon. This is useful if you need to scale
/// the mesh using a matrix multiply, or just for modifying the type of each
/// vertex.
pub trait MapToVertices<T, U> {
    /// from a iterator of polygons, produces a iterator of polygons. Each
    /// vertex in the process is modified with the suppled function.
    fn vertex<'a>(self, map: |T|:'a -> U) -> MapToVerticesIter<'a, Self, T, U>;
}

impl<VIn, VOut, P, POut: MapVertex<VIn, VOut, P>, T: Iterator<POut>>
    MapToVertices<VIn, VOut> for T {
    fn vertex<'a>(self, map: |VIn|:'a -> VOut) -> MapToVerticesIter<'a, T, VIn, VOut> {
        MapToVerticesIter {
            src: self,
            f: map
        }
    }
}

struct MapToVerticesIter<'a, SRC, T, U> {
    src: SRC,
    f: |T|:'a -> U
}

impl<'a, POut: MapVertex<T, U, P>,
         SRC: Iterator<POut>, T, U, P> Iterator<P> for MapToVerticesIter<'a, SRC, T, U> {
    fn next(&mut self) -> Option<P> {
        self.src.next().map(|x| x.map_vertex(|x| (self.f)(x)))
    }
}<|endoftext|>


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

//! Parsing values.

use std::io::{BufferedReader, IoError, IoErrorKind};
use std::iter::{Peekable};
use value;

/// `CharReader` reads characters one at a time from the given input `Reader`.
struct CharReader<R> {
    reader: BufferedReader<R>
}

impl<R: Reader> CharReader<R> {
    /// Create a new `CharReader` instance.
    pub fn new(reader: R) -> CharReader<R> {
        CharReader {
            reader: BufferedReader::new(reader)
        }
    }
}

impl<R: Reader> Iterator<char> for CharReader<R> {
    /// Returns `Some(c)` for each character `c` from the input reader. Upon
    /// reaching EOF, returns `None`.
    fn next(&mut self) -> Option<char> {
        match self.reader.read_char() {
            Ok(c)                   => Some(c),
            Err(ref e) if is_eof(e) => None,
            Err(e)                  => panic!("IO ERROR! {}", e),
        }
    }
}

/// Return true if the error is reaching the end of file, false otherwise.
fn is_eof(err : &IoError) -> bool {
    err.kind == IoErrorKind::EndOfFile
}

/// Return true if the character is the start of a comment, false otherwise.
fn is_comment(c: &char) -> bool {
    *c == ';'
}

/// Return true if the character is a delimiter between tokens.
fn is_delimiter(c: &char) -> bool {
    c.is_whitespace() || is_comment(c)
}

/// `Read` iteratively parses values from the input `Reader`.
///
/// TODO FITZGEN: rather than panicking on bad input, save an error message and
/// return None or something.
pub struct Read<R> {
    chars: Peekable<char, CharReader<R>>
}

impl<R: Reader> Read<R> {
    /// Create a new `Read` instance from the given `Reader` input source.
    pub fn new(reader: R) -> Read<R> {
        Read {
            chars: CharReader::new(reader).peekable()
        }
    }

    /// Skip to after the next newline character.
    fn skip_line(&mut self) {
        loop {
            match self.chars.peek() {
                None                  => return,
                Some(c) if *c == '\n' => return,
                _                     => { },
            }
            self.chars.next();
        }
    }

    /// Trim initial whitespace and skip comments.
    fn trim(&mut self) {
        loop {
            let skip_line = match self.chars.peek() {
                Some(c) if c.is_whitespace() => false,
                Some(c) if is_comment(c)     => true,
                _                            => return,
            };

            if skip_line {
                self.skip_line();
            } else {
                self.chars.next();
            }
        }
    }
}

impl<R: Reader> Iterator<value::Value> for Read<R> {
    fn next(&mut self) -> Option<value::Value> {
        self.trim();

        let sign : i64 = match self.chars.peek() {
            Some(c) if *c == '-' => -1,
            _                    => 1,
        };

        if sign == -1 {
            self.chars.next();
        }

        let mut abs_value : i64 = match self.chars.next() {
            None    => panic!("Unexpected EOF!"),
            Some(c) => match c.to_digit(10) {
                None    => panic!("Unexpected character: {}", c),
                Some(d) => d as i64
            }
        };

        loop {
            match self.chars.peek() {
                None                       => break,
                Some(c) if is_delimiter(c) => break,
                Some(c)                    => match c.to_digit(10) {
                    None    => panic!("Unexpected character: {}", c),
                    Some(d) => abs_value = (abs_value * 10) + (d as i64),
                }
            }
            self.chars.next();
        }

        Some(value::Value::new_integer(abs_value * sign))
    }
}<commit_msg>Add a test for reading integers<commit_after>// Copyright 2014 Nick Fitzgerald
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Parsing values.

use std::io::{BufferedReader, IoError, IoErrorKind};
use std::iter::{Peekable};
use value;

/// `CharReader` reads characters one at a time from the given input `Reader`.
struct CharReader<R> {
    reader: BufferedReader<R>
}

impl<R: Reader> CharReader<R> {
    /// Create a new `CharReader` instance.
    pub fn new(reader: R) -> CharReader<R> {
        CharReader {
            reader: BufferedReader::new(reader)
        }
    }
}

impl<R: Reader> Iterator<char> for CharReader<R> {
    /// Returns `Some(c)` for each character `c` from the input reader. Upon
    /// reaching EOF, returns `None`.
    fn next(&mut self) -> Option<char> {
        match self.reader.read_char() {
            Ok(c)                   => Some(c),
            Err(ref e) if is_eof(e) => None,
            Err(e)                  => panic!("IO ERROR! {}", e),
        }
    }
}

/// Return true if the error is reaching the end of file, false otherwise.
fn is_eof(err : &IoError) -> bool {
    err.kind == IoErrorKind::EndOfFile
}

/// Return true if the character is the start of a comment, false otherwise.
fn is_comment(c: &char) -> bool {
    *c == ';'
}

/// Return true if the character is a delimiter between tokens.
fn is_delimiter(c: &char) -> bool {
    c.is_whitespace() || is_comment(c)
}

/// `Read` iteratively parses values from the input `Reader`.
///
/// TODO FITZGEN: rather than panicking on bad input, save an error message and
/// return None or something.
pub struct Read<R> {
    chars: Peekable<char, CharReader<R>>
}

impl<R: Reader> Read<R> {
    /// Create a new `Read` instance from the given `Reader` input source.
    pub fn new(reader: R) -> Read<R> {
        Read {
            chars: CharReader::new(reader).peekable()
        }
    }

    /// Skip to after the next newline character.
    fn skip_line(&mut self) {
        loop {
            match self.chars.peek() {
                None                  => return,
                Some(c) if *c == '\n' => return,
                _                     => { },
            }
            self.chars.next();
        }
    }

    /// Trim initial whitespace and skip comments.
    fn trim(&mut self) {
        loop {
            let skip_line = match self.chars.peek() {
                Some(c) if c.is_whitespace() => false,
                Some(c) if is_comment(c)     => true,
                _                            => return,
            };

            if skip_line {
                self.skip_line();
            } else {
                self.chars.next();
            }
        }
    }
}

impl<R: Reader> Iterator<value::Value> for Read<R> {
    fn next(&mut self) -> Option<value::Value> {
        self.trim();

        let sign : i64 = match self.chars.peek() {
            None                 => return None,
            Some(c) if *c == '-' => -1,
            _                    => 1,
        };

        if sign == -1 {
            self.chars.next();
        }

        let mut abs_value : i64 = match self.chars.next() {
            None    => panic!("Unexpected EOF!"),
            Some(c) => match c.to_digit(10) {
                None    => panic!("Unexpected character: {}", c),
                Some(d) => d as i64
            }
        };

        loop {
            match self.chars.peek() {
                None                       => break,
                Some(c) if is_delimiter(c) => break,
                Some(c)                    => match c.to_digit(10) {
                    None    => panic!("Unexpected character: {}", c),
                    Some(d) => abs_value = (abs_value * 10) + (d as i64),
                }
            }
            self.chars.next();
        }

        Some(value::Value::new_integer(abs_value * sign))
    }
}

#[test]
fn test_read_integers() {
    use std::io::MemReader;
    let input = MemReader::new("5 -5 789 -987".to_string().into_bytes());
    let results : Vec<value::Value> = Read::new(input).collect();
    assert_eq!(results, vec!(value::Value::new_integer(5),
                             value::Value::new_integer(-5),
                             value::Value::new_integer(789),
                             value::Value::new_integer(-987)))
}<|endoftext|>


<commit_before>extern crate serde;
extern crate jsonrpc_core;

mod auto_args;
mod util;

#[doc(hidden)]
pub use auto_args::{Wrap, WrapAsync, Trailing};
<commit_msg>Trailing docs<commit_after>extern crate serde;
extern crate jsonrpc_core;

mod auto_args;
mod util;

#[doc(hidden)]
pub use auto_args::{Wrap, WrapAsync};
pub use auto_args::Trailing;
<|endoftext|>