<commit_before>use std::error::Error;
use std::collections::{VecDeque, vec_deque};
use std::str;
use std::cmp;
use std::mem;

use itertools::Itertools;
use rust_htslib::bcf;

pub fn match_variants(matchbcf: &str, max_dist: u32, max_len_diff: u32) -> Result<(), Box<Error>> {
    let mut inbcf = bcf::Reader::from_stdin()?;
    let mut header = bcf::Header::with_template(inbcf.header());

    header.push_record(
        format!("##INFO=<ID=MATCHING,Number=A,Type=Integer,\
        Description=\"For each alternative allele, -1 if it does not match a variant in another VCF/BCF. \
        If it matches a variant, an id i>=0 is points to the i-th variant in the VCF/BCF (counting each \
        alternative allele separately). For indels, matching is fuzzy: distance of centres <= {}, difference of \
        lengths <= {}\">", max_dist, max_len_diff).as_bytes()
    );
    header.push_record(
        format!("##rust-bio-tools={}", env!("CARGO_PKG_VERSION")).as_bytes()
    );
    header.push_record(
        b"##rust-bio-tools-subcommand=vcf-match"
    );
    let mut outbcf = bcf::Writer::from_path(&"-", &header, false, false)?;
    // TODO switch to bcf::RecordBuffer.
    let mut buffer = RecordBuffer::new(bcf::Reader::from_path(&matchbcf)?, max_dist);

    let mut rec = bcf::Record::new();
    let mut i = 0;
    loop {
        if let Err(e) = inbcf.read(&mut rec) {
            if e.is_eof() {
                break;
            }
            return Err(Box::new(e));
        }
        outbcf.translate(&mut rec);

        if let Some(rid) = rec.rid() {
            let chrom = inbcf.header().rid2name(rid);
            let pos = rec.pos();
            // move buffer to pos
            try!(buffer.fill(chrom, pos));

            let var = try!(Variant::new(&mut rec, &mut i));
            let matching = var.alleles.iter().map(|a| {
                for v in buffer.iter() {
                    if let Some(id) = var.matches(v, a, max_dist, max_len_diff) {
                        return id as i32;
                    }
                }
                -1
            }).collect_vec();

            try!(rec.push_info_integer(b"MATCHING", &matching));
            try!(outbcf.write(&rec));
        } else {
            try!(outbcf.write(&rec));
        }

        if (i) % 1000 == 0 {
            info!("{} variants written.", i);
        }
    }
    info!("{} variants written.", i);

    Ok(())
}

#[derive(Debug)]
pub struct Variant {
    id: u32,
    rid: u32,
    pos: u32,
    alleles: Vec<VariantType>
}

impl Variant {

    pub fn new(rec: &mut bcf::Record, id: &mut u32) -> Result<Self, Box<Error>> {
        let pos = rec.pos();

        let svlen = if let Ok(Some(svlen)) = rec.info(b"SVLEN").integer() {
            Some(svlen[0].abs() as u32)
        } else { None };
        let svtype = if let Ok(Some(svtype)) = rec.info(b"SVTYPE").string() {
            Some(svtype[0].to_owned())
        } else { None };
        let end = if let Ok(Some(end)) = rec.info(b"END").integer() {
            Some(end[0] as u32)
        } else { None };
        let inslen = if let Ok(Some(inslen)) = rec.info(b"INSLEN").integer() {
            Some(inslen[0] as u32)
        } else { None };
        let alleles = rec.alleles();
        let refallele = alleles[0];

        let _alleles: Vec<VariantType> = if let Some(svtype) = svtype {
            vec![
                if svtype == b"INS" {
                    let svlen = match (svlen, inslen) {
                        (Some(svlen), _)     => svlen,
                        (None, Some(inslen)) => inslen,
                        _ => {
                            return Err(Box::new(MatchError::MissingTag("SVLEN or INSLEN".to_owned())));
                        }
                    };
                    VariantType::Insertion(svlen)
                } else if svtype == b"DEL" {
                    let svlen = match(svlen, end) {
                        (Some(svlen), _)  => svlen,
                        (None, Some(end)) => end - 1 - pos,
                        _ => {
                            return Err(Box::new(MatchError::MissingTag("SVLEN or END".to_owned())));
                        }
                    };
                    VariantType::Deletion(svlen)
                } else {
                    warn!("Unsupported variant {}", try!(str::from_utf8(&svtype)));
                    VariantType::Unsupported
                }
            ]
        } else {
            let mut _alleles = Vec::with_capacity(alleles.len() - 1);
            for a in &alleles[1..] {
                _alleles.push(
                    if a.len() < refallele.len() {
                        VariantType::Deletion((refallele.len() - a.len()) as u32)
                    } else if a.len() > refallele.len() {
                        VariantType::Insertion((a.len() - refallele.len()) as u32)
                    } else if a.len() == 1 {
                        VariantType::SNV(a[0])
                    } else {
                        warn!("Unsupported variant {} -> {}", try!(str::from_utf8(refallele)), try!(str::from_utf8(a)));
                        VariantType::Unsupported
                    }
                );
            }
            _alleles
        };

        let var = Variant {
            id: *id,
            rid: rec.rid().unwrap(),
            pos: pos,
            alleles: _alleles
        };
        *id += alleles.len() as u32 - 1;
        Ok(var)
    }

    pub fn centerpoint(&self, allele: &VariantType) -> u32 {
        match allele {
            &VariantType::SNV(_) => self.pos,
            &VariantType::Insertion(_) => self.pos,
            &VariantType::Deletion(len) => (self.pos as f64 + len as f64 / 2.0) as u32,
            &VariantType::Unsupported => panic!("Unsupported variant.")
        }
    }

    pub fn matches(&self, other: &Variant, allele: &VariantType, max_dist: u32, max_len_diff: u32) -> Option<u32> {
        if allele.is_unsupported() {
            return None;
        }
        for (j, b) in other.alleles.iter().enumerate() {
            if b.is_unsupported() {
                continue;
            }
            let dist = (self.centerpoint(allele) as i32 - other.centerpoint(b) as i32).abs() as u32;
            match (allele, b) {
                (&VariantType::SNV(a), &VariantType::SNV(b)) => {
                    if a == b && dist == 0 {
                        return Some(other.id(j));
                    }
                },
                (&VariantType::Insertion(l1), &VariantType::Insertion(l2)) |
                (&VariantType::Deletion(l1), &VariantType::Deletion(l2)) => {
                    if (l1 as i32 - l2 as i32).abs() as u32 <= max_len_diff && dist <= max_dist {
                        return Some(other.id(j));
                    }
                },
                // TODO: for now, ignore complex variants
                _ => continue
            }
        }
        None
    }

    pub fn id(&self, allele: usize) -> u32 {
        self.id + allele as u32
    }
}

#[derive(Debug)]
pub enum VariantType {
    SNV(u8),
    Insertion(u32),
    Deletion(u32),
    Unsupported
}

impl VariantType {
    pub fn is_unsupported(&self) -> bool {
        match self {
            &VariantType::Unsupported => true,
            _ => false
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum MatchError {
        MissingTag(tag: String) {
            description("missing tag")
            display("missing tag {}", tag)
        }
    }
}

pub struct RecordBuffer {
    reader: bcf::Reader,
    ringbuffer: VecDeque<Variant>,
    ringbuffer2: VecDeque<Variant>,
    window: u32,
    i: u32
}

impl RecordBuffer {
    pub fn new(reader: bcf::Reader, window: u32) -> Self {
        RecordBuffer {
            reader: reader,
            ringbuffer: VecDeque::new(),
            ringbuffer2: VecDeque::new(),
            window: window,
            i: 0
        }
    }

    pub fn last_rid(&self) -> Option<u32> {
        self.ringbuffer.back().map(|var| var.rid)
    }

    pub fn next_rid(&self) -> Option<u32> {
        self.ringbuffer2.back().map(|var| var.rid)
    }

    fn swap_buffers(&mut self) {
        // swap with buffer for next rid
        mem::swap(&mut self.ringbuffer2, &mut self.ringbuffer);
        // clear second buffer
        self.ringbuffer2.clear();
    }

    fn drain_left(&mut self, rid: u32, window_start: u32) {
        // remove records too far left or from wrong rid
        let to_remove = self.ringbuffer.iter().take_while(|var| var.pos < window_start || var.rid != rid).count();
        self.ringbuffer.drain(..to_remove);
    }

    pub fn fill(&mut self, chrom: &[u8], pos: u32) -> Result<(), Box<Error>> {
        let window_start = cmp::max(pos as i32 - self.window as i32 - 1, 0) as u32;
        let window_end = pos + self.window;
        let rid = try!(self.reader.header().name2rid(chrom));

        match (self.last_rid(), self.next_rid()) {
            (Some(last_rid), _) => {
                if last_rid != rid {
                    self.swap_buffers();
                } else {
                    self.drain_left(rid, window_start);
                }
            },
            (_, Some(_)) => {
                self.swap_buffers();
                self.drain_left(rid, window_start);
            },
            _ => ()
        }

        if !self.ringbuffer2.is_empty() {
            // We have already read beyond the current rid. Hence we can't extend to the right for
            // this rid.
            return Ok(())
        }

        // extend to the right
        let mut rec = bcf::Record::new();
        loop {
            if let Err(e) = self.reader.read(&mut rec) {
                if e.is_eof() {
                    break;
                }
                return Err(Box::new(e));
            }
            let pos = rec.pos();
            let alt_count = rec.alleles().len() as u32 - 1;
            if let Some(rec_rid) = rec.rid() {
                if rec_rid == rid {
                    if pos > window_end {
                        // Record is beyond our window. Store it anyways but stop.
                        self.ringbuffer.push_back(try!(Variant::new(&mut rec, &mut self.i)));
                        break;
                    } else if pos >= window_start {
                        // Record is within our window.
                        self.ringbuffer.push_back(try!(Variant::new(&mut rec, &mut self.i)));
                    } else {
                        // Record is upstream of our window, ignore it
                        self.i += alt_count;
                        continue
                    }
                } else if rec_rid > rid {
                    // record comes from next rid. Store it in second buffer but stop filling.
                    self.ringbuffer2.push_back(try!(Variant::new(&mut rec, &mut self.i)));
                    break;
                } else {
                    // Record comes from previous rid. Ignore it.
                    self.i += alt_count;
                    continue;
                }
            } else {
                // skip records without proper rid
                self.i += alt_count;
                continue;
            }
        }

        Ok(())
    }

    pub fn iter(&self) -> vec_deque::Iter<Variant> {
        self.ringbuffer.iter()
    }
}
<commit_msg>Minor.<commit_after>use std::error::Error;
use std::collections::{VecDeque, vec_deque};
use std::str;
use std::cmp;
use std::mem;

use itertools::Itertools;
use rust_htslib::bcf;

pub fn match_variants(matchbcf: &str, max_dist: u32, max_len_diff: u32) -> Result<(), Box<Error>> {
    let mut inbcf = bcf::Reader::from_stdin()?;
    let mut header = bcf::Header::with_template(inbcf.header());

    header.push_record(
        format!("##INFO=<ID=MATCHING,Number=A,Type=Integer,\
        Description=\"For each alternative allele, -1 if it does not match a variant in another VCF/BCF. \
        If it matches a variant, an id i>=0 points to the i-th variant in the VCF/BCF (counting each \
        alternative allele separately). For indels, matching is fuzzy: distance of centres <= {}, difference of \
        lengths <= {}\">", max_dist, max_len_diff).as_bytes()
    );
    header.push_record(
        format!("##rust-bio-tools={}", env!("CARGO_PKG_VERSION")).as_bytes()
    );
    header.push_record(
        b"##rust-bio-tools-subcommand=vcf-match"
    );
    let mut outbcf = bcf::Writer::from_path(&"-", &header, false, false)?;
    // TODO switch to bcf::RecordBuffer.
    let mut buffer = RecordBuffer::new(bcf::Reader::from_path(&matchbcf)?, max_dist);

    let mut rec = bcf::Record::new();
    let mut i = 0;
    loop {
        if let Err(e) = inbcf.read(&mut rec) {
            if e.is_eof() {
                break;
            }
            return Err(Box::new(e));
        }
        outbcf.translate(&mut rec);

        if let Some(rid) = rec.rid() {
            let chrom = inbcf.header().rid2name(rid);
            let pos = rec.pos();
            // move buffer to pos
            try!(buffer.fill(chrom, pos));

            let var = try!(Variant::new(&mut rec, &mut i));
            let matching = var.alleles.iter().map(|a| {
                for v in buffer.iter() {
                    if let Some(id) = var.matches(v, a, max_dist, max_len_diff) {
                        return id as i32;
                    }
                }
                -1
            }).collect_vec();

            try!(rec.push_info_integer(b"MATCHING", &matching));
            try!(outbcf.write(&rec));
        } else {
            try!(outbcf.write(&rec));
        }

        if (i) % 1000 == 0 {
            info!("{} variants written.", i);
        }
    }
    info!("{} variants written.", i);

    Ok(())
}

#[derive(Debug)]
pub struct Variant {
    id: u32,
    rid: u32,
    pos: u32,
    alleles: Vec<VariantType>
}

impl Variant {

    pub fn new(rec: &mut bcf::Record, id: &mut u32) -> Result<Self, Box<Error>> {
        let pos = rec.pos();

        let svlen = if let Ok(Some(svlen)) = rec.info(b"SVLEN").integer() {
            Some(svlen[0].abs() as u32)
        } else { None };
        let svtype = if let Ok(Some(svtype)) = rec.info(b"SVTYPE").string() {
            Some(svtype[0].to_owned())
        } else { None };
        let end = if let Ok(Some(end)) = rec.info(b"END").integer() {
            Some(end[0] as u32)
        } else { None };
        let inslen = if let Ok(Some(inslen)) = rec.info(b"INSLEN").integer() {
            Some(inslen[0] as u32)
        } else { None };
        let alleles = rec.alleles();
        let refallele = alleles[0];

        let _alleles: Vec<VariantType> = if let Some(svtype) = svtype {
            vec![
                if svtype == b"INS" {
                    let svlen = match (svlen, inslen) {
                        (Some(svlen), _)     => svlen,
                        (None, Some(inslen)) => inslen,
                        _ => {
                            return Err(Box::new(MatchError::MissingTag("SVLEN or INSLEN".to_owned())));
                        }
                    };
                    VariantType::Insertion(svlen)
                } else if svtype == b"DEL" {
                    let svlen = match(svlen, end) {
                        (Some(svlen), _)  => svlen,
                        (None, Some(end)) => end - 1 - pos,
                        _ => {
                            return Err(Box::new(MatchError::MissingTag("SVLEN or END".to_owned())));
                        }
                    };
                    VariantType::Deletion(svlen)
                } else {
                    warn!("Unsupported variant {}", try!(str::from_utf8(&svtype)));
                    VariantType::Unsupported
                }
            ]
        } else {
            let mut _alleles = Vec::with_capacity(alleles.len() - 1);
            for a in &alleles[1..] {
                _alleles.push(
                    if a.len() < refallele.len() {
                        VariantType::Deletion((refallele.len() - a.len()) as u32)
                    } else if a.len() > refallele.len() {
                        VariantType::Insertion((a.len() - refallele.len()) as u32)
                    } else if a.len() == 1 {
                        VariantType::SNV(a[0])
                    } else {
                        warn!("Unsupported variant {} -> {}", try!(str::from_utf8(refallele)), try!(str::from_utf8(a)));
                        VariantType::Unsupported
                    }
                );
            }
            _alleles
        };

        let var = Variant {
            id: *id,
            rid: rec.rid().unwrap(),
            pos: pos,
            alleles: _alleles
        };
        *id += alleles.len() as u32 - 1;
        Ok(var)
    }

    pub fn centerpoint(&self, allele: &VariantType) -> u32 {
        match allele {
            &VariantType::SNV(_) => self.pos,
            &VariantType::Insertion(_) => self.pos,
            &VariantType::Deletion(len) => (self.pos as f64 + len as f64 / 2.0) as u32,
            &VariantType::Unsupported => panic!("Unsupported variant.")
        }
    }

    pub fn matches(&self, other: &Variant, allele: &VariantType, max_dist: u32, max_len_diff: u32) -> Option<u32> {
        if allele.is_unsupported() {
            return None;
        }
        for (j, b) in other.alleles.iter().enumerate() {
            if b.is_unsupported() {
                continue;
            }
            let dist = (self.centerpoint(allele) as i32 - other.centerpoint(b) as i32).abs() as u32;
            match (allele, b) {
                (&VariantType::SNV(a), &VariantType::SNV(b)) => {
                    if a == b && dist == 0 {
                        return Some(other.id(j));
                    }
                },
                (&VariantType::Insertion(l1), &VariantType::Insertion(l2)) |
                (&VariantType::Deletion(l1), &VariantType::Deletion(l2)) => {
                    if (l1 as i32 - l2 as i32).abs() as u32 <= max_len_diff && dist <= max_dist {
                        return Some(other.id(j));
                    }
                },
                // TODO: for now, ignore complex variants
                _ => continue
            }
        }
        None
    }

    pub fn id(&self, allele: usize) -> u32 {
        self.id + allele as u32
    }
}

#[derive(Debug)]
pub enum VariantType {
    SNV(u8),
    Insertion(u32),
    Deletion(u32),
    Unsupported
}

impl VariantType {
    pub fn is_unsupported(&self) -> bool {
        match self {
            &VariantType::Unsupported => true,
            _ => false
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum MatchError {
        MissingTag(tag: String) {
            description("missing tag")
            display("missing tag {}", tag)
        }
    }
}

pub struct RecordBuffer {
    reader: bcf::Reader,
    ringbuffer: VecDeque<Variant>,
    ringbuffer2: VecDeque<Variant>,
    window: u32,
    i: u32
}

impl RecordBuffer {
    pub fn new(reader: bcf::Reader, window: u32) -> Self {
        RecordBuffer {
            reader: reader,
            ringbuffer: VecDeque::new(),
            ringbuffer2: VecDeque::new(),
            window: window,
            i: 0
        }
    }

    pub fn last_rid(&self) -> Option<u32> {
        self.ringbuffer.back().map(|var| var.rid)
    }

    pub fn next_rid(&self) -> Option<u32> {
        self.ringbuffer2.back().map(|var| var.rid)
    }

    fn swap_buffers(&mut self) {
        // swap with buffer for next rid
        mem::swap(&mut self.ringbuffer2, &mut self.ringbuffer);
        // clear second buffer
        self.ringbuffer2.clear();
    }

    fn drain_left(&mut self, rid: u32, window_start: u32) {
        // remove records too far left or from wrong rid
        let to_remove = self.ringbuffer.iter().take_while(|var| var.pos < window_start || var.rid != rid).count();
        self.ringbuffer.drain(..to_remove);
    }

    pub fn fill(&mut self, chrom: &[u8], pos: u32) -> Result<(), Box<Error>> {
        let window_start = cmp::max(pos as i32 - self.window as i32 - 1, 0) as u32;
        let window_end = pos + self.window;
        let rid = try!(self.reader.header().name2rid(chrom));

        match (self.last_rid(), self.next_rid()) {
            (Some(last_rid), _) => {
                if last_rid != rid {
                    self.swap_buffers();
                } else {
                    self.drain_left(rid, window_start);
                }
            },
            (_, Some(_)) => {
                self.swap_buffers();
                self.drain_left(rid, window_start);
            },
            _ => ()
        }

        if !self.ringbuffer2.is_empty() {
            // We have already read beyond the current rid. Hence we can't extend to the right for
            // this rid.
            return Ok(())
        }

        // extend to the right
        let mut rec = bcf::Record::new();
        loop {
            if let Err(e) = self.reader.read(&mut rec) {
                if e.is_eof() {
                    break;
                }
                return Err(Box::new(e));
            }
            let pos = rec.pos();
            let alt_count = rec.alleles().len() as u32 - 1;
            if let Some(rec_rid) = rec.rid() {
                if rec_rid == rid {
                    if pos > window_end {
                        // Record is beyond our window. Store it anyways but stop.
                        self.ringbuffer.push_back(try!(Variant::new(&mut rec, &mut self.i)));
                        break;
                    } else if pos >= window_start {
                        // Record is within our window.
                        self.ringbuffer.push_back(try!(Variant::new(&mut rec, &mut self.i)));
                    } else {
                        // Record is upstream of our window, ignore it
                        self.i += alt_count;
                        continue
                    }
                } else if rec_rid > rid {
                    // record comes from next rid. Store it in second buffer but stop filling.
                    self.ringbuffer2.push_back(try!(Variant::new(&mut rec, &mut self.i)));
                    break;
                } else {
                    // Record comes from previous rid. Ignore it.
                    self.i += alt_count;
                    continue;
                }
            } else {
                // skip records without proper rid
                self.i += alt_count;
                continue;
            }
        }

        Ok(())
    }

    pub fn iter(&self) -> vec_deque::Iter<Variant> {
        self.ringbuffer.iter()
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::env;
use std::iter::repeat;
use std::old_io::File;
use std::old_io::fs::PathExtensions;

use curl::http;
use git2;
use registry::{Registry, NewCrate, NewCrateDependency};
use term::color::BLACK;

use core::source::Source;
use core::{Package, SourceId};
use core::dependency::Kind;
use core::manifest::ManifestMetadata;
use ops;
use sources::{PathSource, RegistrySource};
use util::config;
use util::{CargoResult, human, ChainError, ToUrl};
use util::config::{Config, ConfigValue, Location};
use util::important_paths::find_root_manifest_for_cwd;

pub struct RegistryConfig {
    pub index: Option<String>,
    pub token: Option<String>,
}

pub fn publish(manifest_path: &Path,
               config: &Config,
               token: Option<String>,
               index: Option<String>,
               verify: bool) -> CargoResult<()> {
    let mut src = try!(PathSource::for_path(&manifest_path.dir_path(),
                                            config));
    try!(src.update());
    let pkg = try!(src.root_package());

    let (mut registry, reg_id) = try!(registry(config, token, index));
    try!(verify_dependencies(&pkg, &reg_id));

    // Prepare a tarball, with a non-surpressable warning if metadata
    // is missing since this is being put online.
    let tarball = try!(ops::package(manifest_path, config, verify,
                                    false, true)).unwrap();

    // Upload said tarball to the specified destination
    try!(config.shell().status("Uploading", pkg.package_id().to_string()));
    try!(transmit(&pkg, &tarball, &mut registry));

    Ok(())
}

fn verify_dependencies(pkg: &Package, registry_src: &SourceId)
                       -> CargoResult<()> {
    for dep in pkg.dependencies().iter() {
        if dep.source_id().is_path() {
            if dep.specified_req().is_none() {
                return Err(human(format!("all path dependencies must have \
                                          a version specified when \
                                          publishing.\n\
                                          dependency `{}` does not specify \
                                          a version", dep.name())))
            }
        } else if dep.source_id() != registry_src {
            return Err(human(format!("all dependencies must come from the \
                                      same source.\ndependency `{}` comes \
                                      from {} instead", dep.name(),
                                     dep.source_id())))
        }
    }
    Ok(())
}

fn transmit(pkg: &Package, tarball: &Path, registry: &mut Registry)
            -> CargoResult<()> {
    let deps = pkg.dependencies().iter().map(|dep| {
        NewCrateDependency {
            optional: dep.is_optional(),
            default_features: dep.uses_default_features(),
            name: dep.name().to_string(),
            features: dep.features().to_vec(),
            version_req: dep.version_req().to_string(),
            target: dep.only_for_platform().map(|s| s.to_string()),
            kind: match dep.kind() {
                Kind::Normal => "normal",
                Kind::Build => "build",
                Kind::Development => "dev",
            }.to_string(),
        }
    }).collect::<Vec<NewCrateDependency>>();
    let manifest = pkg.manifest();
    let ManifestMetadata {
        ref authors, ref description, ref homepage, ref documentation,
        ref keywords, ref readme, ref repository, ref license, ref license_file,
    } = *manifest.metadata();
    let readme = match *readme {
        Some(ref readme) => {
            let path = pkg.root().join(readme);
            Some(try!(File::open(&path).read_to_string().chain_error(|| {
                human("failed to read the specified README")
            })))
        }
        None => None,
    };
    match *license_file {
        Some(ref file) => {
            if !pkg.root().join(file).exists() {
                return Err(human(format!("the license file `{}` does not exist",
                                         file)))
            }
        }
        None => {}
    }
    registry.publish(&NewCrate {
        name: pkg.name().to_string(),
        vers: pkg.version().to_string(),
        deps: deps,
        features: pkg.summary().features().clone(),
        authors: authors.clone(),
        description: description.clone(),
        homepage: homepage.clone(),
        documentation: documentation.clone(),
        keywords: keywords.clone(),
        readme: readme,
        repository: repository.clone(),
        license: license.clone(),
        license_file: license_file.clone(),
    }, tarball).map_err(|e| {
        human(e.to_string())
    })
}

pub fn registry_configuration(config: &Config) -> CargoResult<RegistryConfig> {
    let index = try!(config.get_string("registry.index")).map(|p| p.0);
    let token = try!(config.get_string("registry.token")).map(|p| p.0);
    Ok(RegistryConfig { index: index, token: token })
}

pub fn registry(config: &Config,
                token: Option<String>,
                index: Option<String>) -> CargoResult<(Registry, SourceId)> {
    // Parse all configuration options
    let RegistryConfig {
        token: token_config,
        index: index_config,
    } = try!(registry_configuration(config));
    let token = token.or(token_config);
    let index = index.or(index_config).unwrap_or(RegistrySource::default_url());
    let index = try!(index.to_url().map_err(human));
    let sid = SourceId::for_registry(&index);
    let api_host = {
        let mut src = RegistrySource::new(&sid, config);
        try!(src.update().chain_error(|| {
            human(format!("Failed to update registry {}", index))
        }));
        (try!(src.config())).api
    };
    let handle = try!(http_handle(config));
    Ok((Registry::new_handle(api_host, token, handle), sid))
}

/// Create a new HTTP handle with appropriate global configuration for cargo.
pub fn http_handle(config: &Config) -> CargoResult<http::Handle> {
    let handle = http::handle().timeout(60);
    let handle = match try!(http_proxy(config)) {
        Some(proxy) => handle.proxy(proxy),
        None => handle,
    };
    let handle = match try!(http_timeout(config)) {
        Some(timeout) => handle.timeout(timeout as usize),
        None => handle,
    };
    Ok(handle)
}

/// Find an explicit HTTP proxy if one is available.
///
/// Favor cargo's `http.proxy`, then git's `http.proxy`. Proxies specified
/// via environment variables are picked up by libcurl.
fn http_proxy(config: &Config) -> CargoResult<Option<String>> {
    match try!(config.get_string("http.proxy")) {
        Some((s, _)) => return Ok(Some(s)),
        None => {}
    }
    match git2::Config::open_default() {
        Ok(cfg) => {
            match cfg.get_str("http.proxy") {
                Ok(s) => return Ok(Some(s.to_string())),
                Err(..) => {}
            }
        }
        Err(..) => {}
    }
    Ok(None)
}

/// Determine if an http proxy exists.
///
/// Checks the following for existence, in order:
///
/// * cargo's `http.proxy`
/// * git's `http.proxy`
/// * http_proxy env var
/// * HTTP_PROXY env var
/// * https_proxy env var
/// * HTTPS_PROXY env var
pub fn http_proxy_exists(config: &Config) -> CargoResult<bool> {
    if try!(http_proxy(config)).is_some() {
        Ok(true)
    } else {
        Ok(["http_proxy", "HTTP_PROXY",
           "https_proxy", "HTTPS_PROXY"].iter().any(|v| env::var(v).is_ok()))
    }
}

pub fn http_timeout(config: &Config) -> CargoResult<Option<i64>> {
    match try!(config.get_i64("http.timeout")) {
        Some((s, _)) => return Ok(Some(s)),
        None => {}
    }
    Ok(env::var("HTTP_TIMEOUT").ok().and_then(|s| s.parse().ok()))
}

pub fn registry_login(config: &Config, token: String) -> CargoResult<()> {
    let RegistryConfig { index, token: _ } = try!(registry_configuration(config));
    let mut map = HashMap::new();
    let p = config.cwd().clone();
    match index {
        Some(index) => {
            map.insert("index".to_string(), ConfigValue::String(index, p.clone()));
        }
        None => {}
    }
    map.insert("token".to_string(), ConfigValue::String(token, p));

    config::set_config(config, Location::Global, "registry",
                       ConfigValue::Table(map, Path::new(".")))
}

pub struct OwnersOptions {
    pub krate: Option<String>,
    pub token: Option<String>,
    pub index: Option<String>,
    pub to_add: Option<Vec<String>>,
    pub to_remove: Option<Vec<String>>,
    pub list: bool,
}

pub fn modify_owners(config: &Config, opts: &OwnersOptions) -> CargoResult<()> {
    let name = match opts.krate {
        Some(ref name) => name.clone(),
        None => {
            let manifest_path = try!(find_root_manifest_for_cwd(None));
            let mut src = try!(PathSource::for_path(&manifest_path.dir_path(),
                                                    config));
            try!(src.update());
            let pkg = try!(src.root_package());
            pkg.name().to_string()
        }
    };

    let (mut registry, _) = try!(registry(config, opts.token.clone(),
                                          opts.index.clone()));

    match opts.to_add {
        Some(ref v) => {
            let v = v.iter().map(|s| s.as_slice()).collect::<Vec<_>>();
            try!(config.shell().status("Owner", format!("adding `{:#?}` to `{}`",
                                                        v, name)));
            try!(registry.add_owners(&name, &v).map_err(|e| {
                human(format!("failed to add owners: {}", e))
            }));
        }
        None => {}
    }

    match opts.to_remove {
        Some(ref v) => {
            let v = v.iter().map(|s| s.as_slice()).collect::<Vec<_>>();
            try!(config.shell().status("Owner", format!("removing `{:?}` from `{}`",
                                                        v, name)));
            try!(registry.remove_owners(&name, &v).map_err(|e| {
                human(format!("failed to add owners: {}", e))
            }));
        }
        None => {}
    }

    if opts.list {
        let owners = try!(registry.list_owners(&name).map_err(|e| {
            human(format!("failed to list owners: {}", e))
        }));
        for owner in owners.iter() {
            print!("{}", owner.login);
            match (owner.name.as_ref(), owner.email.as_ref()) {
                (Some(name), Some(email)) => println!(" ({} <{}>)", name, email),
                (Some(s), None) |
                (None, Some(s)) => println!(" ({})", s),
                (None, None) => println!(""),
            }
        }
    }

    Ok(())
}

pub fn yank(config: &Config,
            krate: Option<String>,
            version: Option<String>,
            token: Option<String>,
            index: Option<String>,
            undo: bool) -> CargoResult<()> {
    let name = match krate {
        Some(name) => name,
        None => {
            let manifest_path = try!(find_root_manifest_for_cwd(None));
            let mut src = try!(PathSource::for_path(&manifest_path.dir_path(),
                                                    config));
            try!(src.update());
            let pkg = try!(src.root_package());
            pkg.name().to_string()
        }
    };
    let version = match version {
        Some(v) => v,
        None => return Err(human("a version must be specified to yank"))
    };

    let (mut registry, _) = try!(registry(config, token, index));

    if undo {
        try!(config.shell().status("Unyank", format!("{}:{}", name, version)));
        try!(registry.unyank(&name, &version).map_err(|e| {
            human(format!("failed to undo a yank: {}", e))
        }));
    } else {
        try!(config.shell().status("Yank", format!("{}:{}", name, version)));
        try!(registry.yank(&name, &version).map_err(|e| {
            human(format!("failed to yank: {}", e))
        }));
    }

    Ok(())
}

pub fn search(query: &str, config: &Config, index: Option<String>) -> CargoResult<()> {
    fn truncate_with_ellipsis(s: &str, max_length: usize) -> String {
        if s.len() < max_length {
            s.to_string()
        } else {
            format!("{}…", &s[..max_length - 1])
        }
    }

    let (mut registry, _) = try!(registry(config, None, index));
    let crates = try!(registry.search(query).map_err(|e| {
        human(format!("failed to retrieve search results from the registry: {}", e))
    }));

    let list_items = crates.iter()
        .map(|krate| (
            format!("{} ({})", krate.name, krate.max_version),
            krate.description.as_ref().map(|desc|
                truncate_with_ellipsis(&desc.replace("\n", " "), 128))
        ))
        .collect::<Vec<_>>();
    let description_margin = list_items.iter()
        .map(|&(ref left, _)| left.len() + 4)
        .max()
        .unwrap_or(0);

    for (name, description) in list_items.into_iter() {
        let line = match description {
            Some(desc) => {
                let space = repeat(' ').take(description_margin - name.len())
                                       .collect::<String>();
                name.to_string() + &space + &desc
            }
            None => name
        };
        try!(config.shell().say(line, BLACK));
    }

    Ok(())
}
<commit_msg>Don't time out after 0.006 seconds<commit_after>use std::collections::HashMap;
use std::env;
use std::iter::repeat;
use std::old_io::File;
use std::old_io::fs::PathExtensions;

use curl::http;
use git2;
use registry::{Registry, NewCrate, NewCrateDependency};
use term::color::BLACK;

use core::source::Source;
use core::{Package, SourceId};
use core::dependency::Kind;
use core::manifest::ManifestMetadata;
use ops;
use sources::{PathSource, RegistrySource};
use util::config;
use util::{CargoResult, human, ChainError, ToUrl};
use util::config::{Config, ConfigValue, Location};
use util::important_paths::find_root_manifest_for_cwd;

pub struct RegistryConfig {
    pub index: Option<String>,
    pub token: Option<String>,
}

pub fn publish(manifest_path: &Path,
               config: &Config,
               token: Option<String>,
               index: Option<String>,
               verify: bool) -> CargoResult<()> {
    let mut src = try!(PathSource::for_path(&manifest_path.dir_path(),
                                            config));
    try!(src.update());
    let pkg = try!(src.root_package());

    let (mut registry, reg_id) = try!(registry(config, token, index));
    try!(verify_dependencies(&pkg, &reg_id));

    // Prepare a tarball, with a non-surpressable warning if metadata
    // is missing since this is being put online.
    let tarball = try!(ops::package(manifest_path, config, verify,
                                    false, true)).unwrap();

    // Upload said tarball to the specified destination
    try!(config.shell().status("Uploading", pkg.package_id().to_string()));
    try!(transmit(&pkg, &tarball, &mut registry));

    Ok(())
}

fn verify_dependencies(pkg: &Package, registry_src: &SourceId)
                       -> CargoResult<()> {
    for dep in pkg.dependencies().iter() {
        if dep.source_id().is_path() {
            if dep.specified_req().is_none() {
                return Err(human(format!("all path dependencies must have \
                                          a version specified when \
                                          publishing.\n\
                                          dependency `{}` does not specify \
                                          a version", dep.name())))
            }
        } else if dep.source_id() != registry_src {
            return Err(human(format!("all dependencies must come from the \
                                      same source.\ndependency `{}` comes \
                                      from {} instead", dep.name(),
                                     dep.source_id())))
        }
    }
    Ok(())
}

fn transmit(pkg: &Package, tarball: &Path, registry: &mut Registry)
            -> CargoResult<()> {
    let deps = pkg.dependencies().iter().map(|dep| {
        NewCrateDependency {
            optional: dep.is_optional(),
            default_features: dep.uses_default_features(),
            name: dep.name().to_string(),
            features: dep.features().to_vec(),
            version_req: dep.version_req().to_string(),
            target: dep.only_for_platform().map(|s| s.to_string()),
            kind: match dep.kind() {
                Kind::Normal => "normal",
                Kind::Build => "build",
                Kind::Development => "dev",
            }.to_string(),
        }
    }).collect::<Vec<NewCrateDependency>>();
    let manifest = pkg.manifest();
    let ManifestMetadata {
        ref authors, ref description, ref homepage, ref documentation,
        ref keywords, ref readme, ref repository, ref license, ref license_file,
    } = *manifest.metadata();
    let readme = match *readme {
        Some(ref readme) => {
            let path = pkg.root().join(readme);
            Some(try!(File::open(&path).read_to_string().chain_error(|| {
                human("failed to read the specified README")
            })))
        }
        None => None,
    };
    match *license_file {
        Some(ref file) => {
            if !pkg.root().join(file).exists() {
                return Err(human(format!("the license file `{}` does not exist",
                                         file)))
            }
        }
        None => {}
    }
    registry.publish(&NewCrate {
        name: pkg.name().to_string(),
        vers: pkg.version().to_string(),
        deps: deps,
        features: pkg.summary().features().clone(),
        authors: authors.clone(),
        description: description.clone(),
        homepage: homepage.clone(),
        documentation: documentation.clone(),
        keywords: keywords.clone(),
        readme: readme,
        repository: repository.clone(),
        license: license.clone(),
        license_file: license_file.clone(),
    }, tarball).map_err(|e| {
        human(e.to_string())
    })
}

pub fn registry_configuration(config: &Config) -> CargoResult<RegistryConfig> {
    let index = try!(config.get_string("registry.index")).map(|p| p.0);
    let token = try!(config.get_string("registry.token")).map(|p| p.0);
    Ok(RegistryConfig { index: index, token: token })
}

pub fn registry(config: &Config,
                token: Option<String>,
                index: Option<String>) -> CargoResult<(Registry, SourceId)> {
    // Parse all configuration options
    let RegistryConfig {
        token: token_config,
        index: index_config,
    } = try!(registry_configuration(config));
    let token = token.or(token_config);
    let index = index.or(index_config).unwrap_or(RegistrySource::default_url());
    let index = try!(index.to_url().map_err(human));
    let sid = SourceId::for_registry(&index);
    let api_host = {
        let mut src = RegistrySource::new(&sid, config);
        try!(src.update().chain_error(|| {
            human(format!("Failed to update registry {}", index))
        }));
        (try!(src.config())).api
    };
    let handle = try!(http_handle(config));
    Ok((Registry::new_handle(api_host, token, handle), sid))
}

/// Create a new HTTP handle with appropriate global configuration for cargo.
pub fn http_handle(config: &Config) -> CargoResult<http::Handle> {
    let handle = http::handle().timeout(60_000);
    let handle = match try!(http_proxy(config)) {
        Some(proxy) => handle.proxy(proxy),
        None => handle,
    };
    let handle = match try!(http_timeout(config)) {
        Some(timeout) => handle.timeout(timeout as usize),
        None => handle,
    };
    Ok(handle)
}

/// Find an explicit HTTP proxy if one is available.
///
/// Favor cargo's `http.proxy`, then git's `http.proxy`. Proxies specified
/// via environment variables are picked up by libcurl.
fn http_proxy(config: &Config) -> CargoResult<Option<String>> {
    match try!(config.get_string("http.proxy")) {
        Some((s, _)) => return Ok(Some(s)),
        None => {}
    }
    match git2::Config::open_default() {
        Ok(cfg) => {
            match cfg.get_str("http.proxy") {
                Ok(s) => return Ok(Some(s.to_string())),
                Err(..) => {}
            }
        }
        Err(..) => {}
    }
    Ok(None)
}

/// Determine if an http proxy exists.
///
/// Checks the following for existence, in order:
///
/// * cargo's `http.proxy`
/// * git's `http.proxy`
/// * http_proxy env var
/// * HTTP_PROXY env var
/// * https_proxy env var
/// * HTTPS_PROXY env var
pub fn http_proxy_exists(config: &Config) -> CargoResult<bool> {
    if try!(http_proxy(config)).is_some() {
        Ok(true)
    } else {
        Ok(["http_proxy", "HTTP_PROXY",
           "https_proxy", "HTTPS_PROXY"].iter().any(|v| env::var(v).is_ok()))
    }
}

pub fn http_timeout(config: &Config) -> CargoResult<Option<i64>> {
    match try!(config.get_i64("http.timeout")) {
        Some((s, _)) => return Ok(Some(s)),
        None => {}
    }
    Ok(env::var("HTTP_TIMEOUT").ok().and_then(|s| s.parse().ok()))
}

pub fn registry_login(config: &Config, token: String) -> CargoResult<()> {
    let RegistryConfig { index, token: _ } = try!(registry_configuration(config));
    let mut map = HashMap::new();
    let p = config.cwd().clone();
    match index {
        Some(index) => {
            map.insert("index".to_string(), ConfigValue::String(index, p.clone()));
        }
        None => {}
    }
    map.insert("token".to_string(), ConfigValue::String(token, p));

    config::set_config(config, Location::Global, "registry",
                       ConfigValue::Table(map, Path::new(".")))
}

pub struct OwnersOptions {
    pub krate: Option<String>,
    pub token: Option<String>,
    pub index: Option<String>,
    pub to_add: Option<Vec<String>>,
    pub to_remove: Option<Vec<String>>,
    pub list: bool,
}

pub fn modify_owners(config: &Config, opts: &OwnersOptions) -> CargoResult<()> {
    let name = match opts.krate {
        Some(ref name) => name.clone(),
        None => {
            let manifest_path = try!(find_root_manifest_for_cwd(None));
            let mut src = try!(PathSource::for_path(&manifest_path.dir_path(),
                                                    config));
            try!(src.update());
            let pkg = try!(src.root_package());
            pkg.name().to_string()
        }
    };

    let (mut registry, _) = try!(registry(config, opts.token.clone(),
                                          opts.index.clone()));

    match opts.to_add {
        Some(ref v) => {
            let v = v.iter().map(|s| s.as_slice()).collect::<Vec<_>>();
            try!(config.shell().status("Owner", format!("adding `{:#?}` to `{}`",
                                                        v, name)));
            try!(registry.add_owners(&name, &v).map_err(|e| {
                human(format!("failed to add owners: {}", e))
            }));
        }
        None => {}
    }

    match opts.to_remove {
        Some(ref v) => {
            let v = v.iter().map(|s| s.as_slice()).collect::<Vec<_>>();
            try!(config.shell().status("Owner", format!("removing `{:?}` from `{}`",
                                                        v, name)));
            try!(registry.remove_owners(&name, &v).map_err(|e| {
                human(format!("failed to add owners: {}", e))
            }));
        }
        None => {}
    }

    if opts.list {
        let owners = try!(registry.list_owners(&name).map_err(|e| {
            human(format!("failed to list owners: {}", e))
        }));
        for owner in owners.iter() {
            print!("{}", owner.login);
            match (owner.name.as_ref(), owner.email.as_ref()) {
                (Some(name), Some(email)) => println!(" ({} <{}>)", name, email),
                (Some(s), None) |
                (None, Some(s)) => println!(" ({})", s),
                (None, None) => println!(""),
            }
        }
    }

    Ok(())
}

pub fn yank(config: &Config,
            krate: Option<String>,
            version: Option<String>,
            token: Option<String>,
            index: Option<String>,
            undo: bool) -> CargoResult<()> {
    let name = match krate {
        Some(name) => name,
        None => {
            let manifest_path = try!(find_root_manifest_for_cwd(None));
            let mut src = try!(PathSource::for_path(&manifest_path.dir_path(),
                                                    config));
            try!(src.update());
            let pkg = try!(src.root_package());
            pkg.name().to_string()
        }
    };
    let version = match version {
        Some(v) => v,
        None => return Err(human("a version must be specified to yank"))
    };

    let (mut registry, _) = try!(registry(config, token, index));

    if undo {
        try!(config.shell().status("Unyank", format!("{}:{}", name, version)));
        try!(registry.unyank(&name, &version).map_err(|e| {
            human(format!("failed to undo a yank: {}", e))
        }));
    } else {
        try!(config.shell().status("Yank", format!("{}:{}", name, version)));
        try!(registry.yank(&name, &version).map_err(|e| {
            human(format!("failed to yank: {}", e))
        }));
    }

    Ok(())
}

pub fn search(query: &str, config: &Config, index: Option<String>) -> CargoResult<()> {
    fn truncate_with_ellipsis(s: &str, max_length: usize) -> String {
        if s.len() < max_length {
            s.to_string()
        } else {
            format!("{}…", &s[..max_length - 1])
        }
    }

    let (mut registry, _) = try!(registry(config, None, index));
    let crates = try!(registry.search(query).map_err(|e| {
        human(format!("failed to retrieve search results from the registry: {}", e))
    }));

    let list_items = crates.iter()
        .map(|krate| (
            format!("{} ({})", krate.name, krate.max_version),
            krate.description.as_ref().map(|desc|
                truncate_with_ellipsis(&desc.replace("\n", " "), 128))
        ))
        .collect::<Vec<_>>();
    let description_margin = list_items.iter()
        .map(|&(ref left, _)| left.len() + 4)
        .max()
        .unwrap_or(0);

    for (name, description) in list_items.into_iter() {
        let line = match description {
            Some(desc) => {
                let space = repeat(' ').take(description_margin - name.len())
                                       .collect::<String>();
                name.to_string() + &space + &desc
            }
            None => name
        };
        try!(config.shell().say(line, BLACK));
    }

    Ok(())
}
<|endoftext|>


<commit_before>use base::{
    AbstractCFType,
    AbstractCFTypeRef,
    CFAllocatorRef,
    CFIndex,
    CFRange,
    CFRelease,
    CFTypeRef,
    kCFAllocatorDefault,
};
use libc::c_void;

pub type CFArrayRetainCallBack = *u8;
pub type CFArrayReleaseCallBack = *u8;
pub type CFArrayCopyDescriptionCallBack = *u8;
pub type CFArrayEqualCallBack = *u8;

pub struct CFArrayCallBacks {
    version: CFIndex,
    retain: CFArrayRetainCallBack,
    release: CFArrayReleaseCallBack,
    copyDescription: CFArrayCopyDescriptionCallBack,
    equal: CFArrayEqualCallBack,
}

struct __CFArray { private: () }
pub type CFArrayRef = *__CFArray;

impl CFArrayRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
}

struct CFArray<ElemRefType : AbstractCFTypeRef,
               ElemType    : AbstractCFType<ElemRefType>> {
    obj: CFArrayRef,

    drop {
        unsafe {
            CFRelease(cast::transmute(self.obj))
        }
    }
}

pub impl<ElemRefType : AbstractCFTypeRef,
         ElemType    : AbstractCFType<ElemRefType>>
    CFArray<ElemRefType, ElemType> {
    static fn new(elems: &[ElemType]) -> CFArray<ElemRefType, ElemType> {
        let array_ref : CFArrayRef;

        let elems_refs = do vec::map(elems) |e: &ElemType| { e.get_ref().as_type_ref() };

        unsafe {
            array_ref = CFArrayCreate(kCFAllocatorDefault,
                                      cast::transmute(vec::raw::to_ptr(elems_refs)),
                                      elems.len() as CFIndex,
                                      ptr::to_unsafe_ptr(&kCFTypeArrayCallBacks));
        }
        // return CFArray::wrap(array_ref)
        return CFArray { obj: array_ref };
    }

    pub fn each_ref<A>(cb: fn&(ElemRefType) -> A) {
        for uint::range(0, self.len()) |i| { cb(self[i]); }
    }

    pub fn eachi_ref<A>(cb: fn&(uint, ElemRefType) -> A) {
        for uint::range(0, self.len()) |i| { cb(i, self[i]); }
    }

    pub fn each<A>(cb: fn&(&ElemType) -> A) {
        for uint::range(0, self.len()) |i| { cb(&base::wrap(self[i])); }
    }

    pub fn eachi<A>(cb: fn&(uint, &ElemType) -> A) {
        for uint::range(0, self.len()) |i| { cb(i, &base::wrap(self[i])); }
    }

    pub pure fn len() -> uint {
        unsafe { return CFArrayGetCount(self.obj) as uint; }
    }
}

pub impl<ElemRefType : AbstractCFTypeRef,
         ElemType    : AbstractCFType<ElemRefType>>
    CFArray<ElemRefType, ElemType> : AbstractCFType<CFArrayRef> {

    pure fn get_ref() -> CFArrayRef { self.obj }

    static fn wrap(obj: CFArrayRef) -> CFArray<ElemRefType, ElemType> {
        CFArray { obj: obj }
    }

    static fn unwrap(wrapper: CFArray<ElemRefType, ElemType>) -> CFArrayRef {
        wrapper.obj
    }
}

pub impl<ElemRefType : AbstractCFTypeRef,
         ElemType    : AbstractCFType<ElemRefType>>
    CFArray<ElemRefType, ElemType> : Index<uint, ElemRefType> {
    pure fn index(idx: uint) -> ElemRefType {
        assert idx < self.len();
        unsafe {
            let elem = CFArrayGetValueAtIndex(self.obj, idx as CFIndex);
            // Don't return a wrapped thing, since we don't know whether
            // it needs base::wrap() or base::wrap_borrowed()
            return cast::transmute(elem);
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFArray.h
     */
    const kCFTypeArrayCallBacks: CFArrayCallBacks;

    fn CFArrayCreate(allocator: CFAllocatorRef, values: **c_void,
                     numValues: CFIndex, callBacks: *CFArrayCallBacks) -> CFArrayRef;

    fn CFArrayGetValueAtIndex(theArray: CFArrayRef, idx: CFIndex) -> *c_void;
    fn CFArrayGetCount(theArray: CFArrayRef) -> CFIndex;
}

#[test]
fn should_box_and_unbox() {
    use number::{CFNumber, CFNumberRef};

    let arr = CFArray::new([
        CFNumber::new(1 as i32),
        CFNumber::new(2 as i32),
        CFNumber::new(3 as i32),
        CFNumber::new(4 as i32),
        CFNumber::new(5 as i32)]);

    let mut sum = 0i32;
    // TODO: not always safe to re-wrap, unless we addref the element
    for arr.each |elem| {
        sum += elem.to_i32();
    }

    assert sum == 15;

    for arr.each_ref |elem: CFNumberRef| {
        let n: CFNumber = base::wrap(elem);
        sum += n.to_i32();
    }

    assert sum == 30;
}<commit_msg>Retain elements when iterating over an array<commit_after>use base::{
    AbstractCFType,
    AbstractCFTypeRef,
    CFAllocatorRef,
    CFIndex,
    CFRange,
    CFRelease,
    CFTypeRef,
    kCFAllocatorDefault,
};
use libc::c_void;

pub type CFArrayRetainCallBack = *u8;
pub type CFArrayReleaseCallBack = *u8;
pub type CFArrayCopyDescriptionCallBack = *u8;
pub type CFArrayEqualCallBack = *u8;

pub struct CFArrayCallBacks {
    version: CFIndex,
    retain: CFArrayRetainCallBack,
    release: CFArrayReleaseCallBack,
    copyDescription: CFArrayCopyDescriptionCallBack,
    equal: CFArrayEqualCallBack,
}

struct __CFArray { private: () }
pub type CFArrayRef = *__CFArray;

impl CFArrayRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
}

struct CFArray<ElemRefType : AbstractCFTypeRef,
               ElemType    : AbstractCFType<ElemRefType>> {
    obj: CFArrayRef,

    drop {
        unsafe {
            CFRelease(cast::transmute(self.obj))
        }
    }
}

pub impl<ElemRefType : AbstractCFTypeRef,
         ElemType    : AbstractCFType<ElemRefType>>
    CFArray<ElemRefType, ElemType> {
    static fn new(elems: &[ElemType]) -> CFArray<ElemRefType, ElemType> {
        let array_ref : CFArrayRef;

        let elems_refs = do vec::map(elems) |e: &ElemType| { e.get_ref().as_type_ref() };

        unsafe {
            array_ref = CFArrayCreate(kCFAllocatorDefault,
                                      cast::transmute(vec::raw::to_ptr(elems_refs)),
                                      elems.len() as CFIndex,
                                      ptr::to_unsafe_ptr(&kCFTypeArrayCallBacks));
        }
        // return CFArray::wrap(array_ref)
        return CFArray { obj: array_ref };
    }

    pub fn each_ref<A>(cb: fn&(ElemRefType) -> A) {
        for uint::range(0, self.len()) |i| { cb(self[i]); }
    }

    pub fn eachi_ref<A>(cb: fn&(uint, ElemRefType) -> A) {
        for uint::range(0, self.len()) |i| { cb(i, self[i]); }
    }

    pub fn each<A>(cb: fn&(&ElemType) -> A) {
        for uint::range(0, self.len()) |i| {
            // NB: Rewrapping means that we must retain again.
            let elem = self[i];
            base::CFRetain(elem.as_type_ref());
            cb(&base::wrap(move elem));
        }
    }

    pub fn eachi<A>(cb: fn&(uint, &ElemType) -> A) {
        for uint::range(0, self.len()) |i| {
            let elem = self[i];
            base::CFRetain(elem.as_type_ref());
            cb(i, &base::wrap(move elem));
        }
    }

    pub pure fn len() -> uint {
        unsafe { return CFArrayGetCount(self.obj) as uint; }
    }
}

pub impl<ElemRefType : AbstractCFTypeRef,
         ElemType    : AbstractCFType<ElemRefType>>
    CFArray<ElemRefType, ElemType> : AbstractCFType<CFArrayRef> {

    pure fn get_ref() -> CFArrayRef { self.obj }

    static fn wrap(obj: CFArrayRef) -> CFArray<ElemRefType, ElemType> {
        CFArray { obj: obj }
    }

    static fn unwrap(wrapper: CFArray<ElemRefType, ElemType>) -> CFArrayRef {
        wrapper.obj
    }
}

pub impl<ElemRefType : AbstractCFTypeRef,
         ElemType    : AbstractCFType<ElemRefType>>
    CFArray<ElemRefType, ElemType> : Index<uint, ElemRefType> {
    // NB: This function does *not* retain the element!
    pure fn index(idx: uint) -> ElemRefType {
        assert idx < self.len();
        unsafe {
            let elem = CFArrayGetValueAtIndex(self.obj, idx as CFIndex);
            // Don't return a wrapped thing, since we don't know whether
            // it needs base::wrap() or base::wrap_borrowed()
            return cast::transmute(elem);
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFArray.h
     */
    const kCFTypeArrayCallBacks: CFArrayCallBacks;

    fn CFArrayCreate(allocator: CFAllocatorRef, values: **c_void,
                     numValues: CFIndex, callBacks: *CFArrayCallBacks) -> CFArrayRef;

    fn CFArrayGetValueAtIndex(theArray: CFArrayRef, idx: CFIndex) -> *c_void;
    fn CFArrayGetCount(theArray: CFArrayRef) -> CFIndex;
}

#[test]
fn should_box_and_unbox() {
    use number::{CFNumber, CFNumberRef};

    let arr = CFArray::new([
        CFNumber::new(1 as i32),
        CFNumber::new(2 as i32),
        CFNumber::new(3 as i32),
        CFNumber::new(4 as i32),
        CFNumber::new(5 as i32)]);

    let mut sum = 0i32;
    // TODO: not always safe to re-wrap, unless we addref the element
    for arr.each |elem| {
        sum += elem.to_i32();
    }

    assert sum == 15;

    for arr.each_ref |elem: CFNumberRef| {
        let n: CFNumber = base::wrap(elem);
        sum += n.to_i32();
    }

    assert sum == 30;
}
<|endoftext|>


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

use base::{
    AbstractCFTypeRef,
    CFAllocatorRef,
    CFIndex,
    CFTypeID,
    CFTypeRef,
    CFWrapper,
    kCFAllocatorDefault,
};
use std::cast;
use std::libc::c_void;
use std::ptr;
use std::vec;

pub type CFArrayRetainCallBack = *u8;
pub type CFArrayReleaseCallBack = *u8;
pub type CFArrayCopyDescriptionCallBack = *u8;
pub type CFArrayEqualCallBack = *u8;

pub struct CFArrayCallBacks {
    version: CFIndex,
    retain: CFArrayRetainCallBack,
    release: CFArrayReleaseCallBack,
    copyDescription: CFArrayCopyDescriptionCallBack,
    equal: CFArrayEqualCallBack,
}

struct __CFArray { private: () }
pub type CFArrayRef = *__CFArray;

impl AbstractCFTypeRef for CFArrayRef {
    fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
    fn type_id() -> CFTypeID { unsafe { CFArrayGetTypeID() } }
}

// FIXME: Should be a newtype struct, but that fails due to a Rust compiler bug.
pub struct CFArray<ElemRefType> {
    contents: CFWrapper<CFArrayRef, ElemRefType, ()>
}

impl<ElemRefType:AbstractCFTypeRef> CFArray<ElemRefType> {
    pub fn wrap_shared(array: CFArrayRef) -> CFArray<ElemRefType> {
        CFArray {
            contents: CFWrapper::wrap_shared(array)
        }
    }

    pub fn wrap_owned(array: CFArrayRef) -> CFArray<ElemRefType> {
        CFArray {
            contents: CFWrapper::wrap_owned(array)
        }
    }

    pub fn new(elems: &[ElemRefType]) -> CFArray<ElemRefType> {
        let array_ref: CFArrayRef;
        let elems_refs = do elems.map |e: &ElemRefType| { e.as_type_ref() };

        unsafe {
            array_ref = CFArrayCreate(kCFAllocatorDefault,
                                      cast::transmute::<*CFTypeRef, **c_void>(vec::raw::to_ptr(elems_refs)),
                                      elems.len() as CFIndex,
                                      ptr::to_unsafe_ptr(&kCFTypeArrayCallBacks));
        }

        CFArray {
            contents: CFWrapper::wrap_owned(array_ref)
        }
    }

    pub fn each_ref(&self, cb: &fn(ElemRefType) -> bool) -> bool {
        for i in range(0, self.len()) {
            cb(self[i]);
        }

        true
    }

    pub fn eachi_ref(&self, cb: &fn(uint, ElemRefType) -> bool) -> bool {
        for i in range(0, self.len()) {
            cb(i, self[i]);
        }

        true
    }

    // Careful; the callback must wrap the reference properly.
    // Generally, when array elements are Core Foundation objects (not
    // always true), they need to be wrapped with CFWrapper::wrap_shared.
    pub fn each(&self, cb: &fn(&ElemRefType) -> bool) -> bool {
        for i in range(0, self.len()) {
            cb(&self[i]);
        }

        true
    }

    // Careful; the callback must wrap the reference properly.
    // Generally, when array elements are Core Foundation objects (not
    // always true), they need to be wrapped with CFWrapper::wrap_shared.
    pub fn eachi(&self, cb: &fn(uint, &ElemRefType) -> bool) -> bool{
        for i in range(0, self.len()) {
            cb(i, &self[i]);
        }

        true
    }

    pub fn len(&self) -> uint {
        unsafe {
            return CFArrayGetCount(*self.contents.borrow_ref()) as uint;
        }
    }
}

impl<ElemRefType:AbstractCFTypeRef> Index<uint,ElemRefType> for CFArray<ElemRefType> {
    // Careful; the caller must wrap any returned reference properly.
    // Generally, when array elements are Core Foundation objects (not
    // always true), they need to be wrapped with CFWrapper::wrap_shared.
    fn index(&self, idx: &uint) -> ElemRefType {
        assert!(*idx < self.len());
        unsafe {
            let elem = CFArrayGetValueAtIndex(*self.contents.borrow_ref(), *idx as CFIndex);
            // Don't return a wrapped thing, since we don't know whether
            // it needs base::wrap_shared() or base::wrap_owned()
            cast::transmute::<*c_void,ElemRefType>(elem)
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFArray.h
     */
    static kCFTypeArrayCallBacks: CFArrayCallBacks;

    fn CFArrayCreate(allocator: CFAllocatorRef, values: **c_void,
                     numValues: CFIndex, callBacks: *CFArrayCallBacks) -> CFArrayRef;
    // CFArrayCreateCopy
    // CFArrayBSearchValues
    // CFArrayContainsValue
    fn CFArrayGetCount(theArray: CFArrayRef) -> CFIndex;
    // CFArrayGetCountOfValue
    // CFArrayGetFirstIndexOfValue
    // CFArrayGetLastIndexOfValue
    // CFArrayGetValues
    fn CFArrayGetValueAtIndex(theArray: CFArrayRef, idx: CFIndex) -> *c_void;
    // CFArrayApplyFunction
    fn CFArrayGetTypeID() -> CFTypeID;
}

#[test]
fn should_box_and_unbox() {
    use number::{CFNumber, CFNumberRef};

    let one = CFNumber::new(1 as i32);
    let two = CFNumber::new(2 as i32);
    let thr = CFNumber::new(3 as i32);
    let fou = CFNumber::new(4 as i32);
    let fiv = CFNumber::new(5 as i32);

    let arr = CFArray::new([
        *one.contents.borrow_ref(),
        *two.contents.borrow_ref(),
        *thr.contents.borrow_ref(),
        *fou.contents.borrow_ref(),
        *fiv.contents.borrow_ref()
    ]);

    let mut sum = 0i32;

    for elem in arr.iter() {
        sum += CFNumber::wrap_shared(*elem).to_i32();
    }

    assert!(sum == 15);

    for elem in arr.iter() {
        sum += CFNumber::wrap_shared(*elem).to_i32();
    }

    assert!(sum == 30);
}
<commit_msg>Rewrite CFArray::each as an external iterator<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use base::{
    AbstractCFTypeRef,
    CFAllocatorRef,
    CFIndex,
    CFTypeID,
    CFTypeRef,
    CFWrapper,
    kCFAllocatorDefault,
};
use std::cast;
use std::libc::c_void;
use std::ptr;
use std::vec;
use std::iterator::Enumerate;

pub type CFArrayRetainCallBack = *u8;
pub type CFArrayReleaseCallBack = *u8;
pub type CFArrayCopyDescriptionCallBack = *u8;
pub type CFArrayEqualCallBack = *u8;

pub struct CFArrayCallBacks {
    version: CFIndex,
    retain: CFArrayRetainCallBack,
    release: CFArrayReleaseCallBack,
    copyDescription: CFArrayCopyDescriptionCallBack,
    equal: CFArrayEqualCallBack,
}

struct __CFArray { private: () }
pub type CFArrayRef = *__CFArray;

impl AbstractCFTypeRef for CFArrayRef {
    fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
    fn type_id() -> CFTypeID { unsafe { CFArrayGetTypeID() } }
}

// FIXME: Should be a newtype struct, but that fails due to a Rust compiler bug.
pub struct CFArray<ElemRefType> {
    contents: CFWrapper<CFArrayRef, ElemRefType, ()>
}

pub struct CFArrayIterator<'self, ElemRefType> {
    priv array: &'self CFArray<ElemRefType>,
    priv index: uint,
}

impl<'self, ElemRefType: AbstractCFTypeRef> Iterator<ElemRefType> for CFArrayIterator<'self, ElemRefType> {
    fn next(&mut self) -> Option<ElemRefType> {
        if self.index >= self.array.len() {
            None
        } else {
            let v = self.array[self.index];
            self.index += 1;
            Some(v)
        }
    }
}

impl<ElemRefType:AbstractCFTypeRef> CFArray<ElemRefType> {
    pub fn wrap_shared(array: CFArrayRef) -> CFArray<ElemRefType> {
        CFArray {
            contents: CFWrapper::wrap_shared(array)
        }
    }

    pub fn wrap_owned(array: CFArrayRef) -> CFArray<ElemRefType> {
        CFArray {
            contents: CFWrapper::wrap_owned(array)
        }
    }

    pub fn new(elems: &[ElemRefType]) -> CFArray<ElemRefType> {
        let array_ref: CFArrayRef;
        let elems_refs = do elems.map |e: &ElemRefType| { e.as_type_ref() };

        unsafe {
            array_ref = CFArrayCreate(kCFAllocatorDefault,
                                      cast::transmute::<*CFTypeRef, **c_void>(vec::raw::to_ptr(elems_refs)),
                                      elems.len() as CFIndex,
                                      ptr::to_unsafe_ptr(&kCFTypeArrayCallBacks));
        }

        CFArray {
            contents: CFWrapper::wrap_owned(array_ref)
        }
    }

    // Careful; the loop body must wrap the reference properly.
    // Generally, when array elements are Core Foundation objects (not
    // always true), they need to be wrapped with CFWrapper::wrap_shared.
    pub fn each<'t>(&'t self) -> CFArrayIterator<'t, ElemRefType> {
        CFArrayIterator {
            array: self,
            index: 0
        }
    }

    // Careful; the loop body must wrap the reference properly.
    // Generally, when array elements are Core Foundation objects (not
    // always true), they need to be wrapped with CFWrapper::wrap_shared.
    pub fn eachi<'t>(&'t self) -> Enumerate<CFArrayIterator<'t, ElemRefType>> {
        self.each().enumerate()
    }

    pub fn len(&self) -> uint {
        unsafe {
            return CFArrayGetCount(*self.contents.borrow_ref()) as uint;
        }
    }
}

impl<ElemRefType:AbstractCFTypeRef> Index<uint,ElemRefType> for CFArray<ElemRefType> {
    // Careful; the caller must wrap any returned reference properly.
    // Generally, when array elements are Core Foundation objects (not
    // always true), they need to be wrapped with CFWrapper::wrap_shared.
    fn index(&self, idx: &uint) -> ElemRefType {
        assert!(*idx < self.len());
        unsafe {
            let elem = CFArrayGetValueAtIndex(*self.contents.borrow_ref(), *idx as CFIndex);
            // Don't return a wrapped thing, since we don't know whether
            // it needs base::wrap_shared() or base::wrap_owned()
            cast::transmute::<*c_void,ElemRefType>(elem)
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFArray.h
     */
    static kCFTypeArrayCallBacks: CFArrayCallBacks;

    fn CFArrayCreate(allocator: CFAllocatorRef, values: **c_void,
                     numValues: CFIndex, callBacks: *CFArrayCallBacks) -> CFArrayRef;
    // CFArrayCreateCopy
    // CFArrayBSearchValues
    // CFArrayContainsValue
    fn CFArrayGetCount(theArray: CFArrayRef) -> CFIndex;
    // CFArrayGetCountOfValue
    // CFArrayGetFirstIndexOfValue
    // CFArrayGetLastIndexOfValue
    // CFArrayGetValues
    fn CFArrayGetValueAtIndex(theArray: CFArrayRef, idx: CFIndex) -> *c_void;
    // CFArrayApplyFunction
    fn CFArrayGetTypeID() -> CFTypeID;
}

#[test]
fn should_box_and_unbox() {
    use number::{CFNumber, CFNumberRef};

    let one = CFNumber::new(1 as i32);
    let two = CFNumber::new(2 as i32);
    let thr = CFNumber::new(3 as i32);
    let fou = CFNumber::new(4 as i32);
    let fiv = CFNumber::new(5 as i32);

    let arr = CFArray::new([
        *one.contents.borrow_ref(),
        *two.contents.borrow_ref(),
        *thr.contents.borrow_ref(),
        *fou.contents.borrow_ref(),
        *fiv.contents.borrow_ref()
    ]);

    let mut sum = 0i32;

    for elem in arr.iter() {
        sum += CFNumber::wrap_shared(*elem).to_i32();
    }

    assert!(sum == 15);

    for elem in arr.iter() {
        sum += CFNumber::wrap_shared(*elem).to_i32();
    }

    assert!(sum == 30);
}
<|endoftext|>


<commit_before>#![crate_id = "app"]
#![crate_type = "bin"]
#![deny(warnings, missing_doc)]
#![feature(macro_rules, phase)]

//! A rust-compress application that allows testing of implemented
//! algorithms and their combinations using a simple command line.
//! Example invocations:
//! echo -n "abracadabra" | ./app bwt | xxd
//! echo "banana" | ./app bwt | ./app -d

#[phase(syntax, link)] extern crate log;
extern crate compress;
extern crate collections;

use collections::HashMap;
use std::{io, os, str};
use compress::{bwt, lz4};
use compress::entropy::ari;

static MAGIC    : u32   = 0x73632172;   //=r!cs

struct Config {
    exe_name: ~str,
    methods: Vec<~str>,
    block_size: uint,
    decompress: bool,
}

impl Config {
    fn query(args: &[~str]) -> Config {
        let mut cfg = Config {
            exe_name: args[0].clone(),
            methods: Vec::new(),
            block_size: 1<<16,
            decompress: false,
        };
        let mut handlers: HashMap<&str,|&str, &mut Config|> = HashMap::new();
        handlers.insert("d",|_, cfg| { cfg.decompress = true; });
        handlers.insert("block",|b, cfg| {
            cfg.block_size = from_str(b).unwrap();
        });

        for arg in args.iter().skip(1) {
            if arg.starts_with("-") {
                match handlers.mut_iter().find(|&(&k,_)| arg.slice_from(1).starts_with(k)) {
                    Some((k,h)) => (*h)(arg.slice_from(1+k.len()), &mut cfg),
                    None => println!("Warning: unrecognized option: {}", *arg),
                }
            }else {
                cfg.methods.push(arg.to_owned());
            }
        }
        cfg
    }
}

struct Pass {
    encode: |Box<Writer>, &Config|: 'static -> Box<io::Writer>,
    decode: |Box<Reader>, &Config|: 'static -> Box<io::Reader>,
    info: ~str,
}

/// main entry point
pub fn main() {
    let mut passes: HashMap<~str,Pass> = HashMap::new();
    passes.insert("dummy".to_str(), Pass {
        encode: |w,_| w,
        decode: |r,_| r,
        info: "pass-through".to_str(),
    });
    passes.insert("ari".to_str(), Pass {
        encode: |w,_c| {
            box ari::ByteEncoder::new(w) as Box<Writer>
        },
        decode: |r,_c| {
            box ari::ByteDecoder::new(r) as Box<Reader>
        },
        info: "Adaptive arithmetic byte coder".to_str(),
    });
    passes.insert("bwt".to_str(), Pass {
        encode: |w,c| {
            box bwt::Encoder::new(w, c.block_size) as Box<Writer>
        },
        decode: |r,_c| {
            box bwt::Decoder::new(r, true) as Box<Reader>
        },
        info: "Burrows-Wheeler Transformation".to_str(),
    });
    passes.insert("mtf".to_str(), Pass {
        encode: |w,_c| {
            box bwt::mtf::Encoder::new(w) as Box<Writer>
        },
        decode: |r,_c| {
            box bwt::mtf::Decoder::new(r) as Box<Reader>
        },
        info: "Move-To-Front Transformation".to_str(),
    });
    /* // looks like we are missing the encoder implementation
    passes.insert(~"flate", Pass {
        encode: |w,_c| {
            ~flate::Encoder::new(w, true) as ~Writer
        },
        decode: |r,_c| {
            ~flate::Decoder::new(r, true) as ~Reader
        },
        info: ~"Standardized Ziv-Lempel + Huffman variant",
    });*/
    passes.insert("lz4".to_str(), Pass {
        encode: |w,_c| {
            box lz4::Encoder::new(w) as Box<Writer>
        },
        decode: |r,_c| { // LZ4 decoder seem to work
            box lz4::Decoder::new(r) as Box<Reader>
        },
        info: "Ziv-Lempel derivative, focused at speed".to_str(),
    });

    let config = Config::query(os::args().as_slice());
    let mut input = io::stdin();
    let mut output = io::stdout();
    if config.decompress {
        assert!(config.methods.is_empty(), "Decompression methods are set in stone");
        match input.read_le_u32() {
            Ok(magic) if magic != MAGIC => {
                error!("Input is not a rust-compress archive");
                return
            },
            Err(e) => {
                error!("Unable to read input: {}", e.to_str());
                return
            },
            _ => () //OK
        }
        let methods = Vec::from_fn( input.read_u8().unwrap() as uint, |_| {
            let len = input.read_u8().unwrap() as uint;
            let bytes = input.read_exact(len).unwrap();
            str::from_utf8(bytes.as_slice()).unwrap().to_owned()
        });
        let mut rsum: Box<Reader> = box input;
        for met in methods.iter() {
            info!("Found pass {}", *met);
            match passes.find_mut(met) {
                Some(pa) => rsum = (pa.decode)(rsum, &config),
                None => fail!("Pass is not implemented"),
            }
        }
        io::util::copy(&mut rsum, &mut output).unwrap();
    }else if config.methods.is_empty() {
        println!("rust-compress test application");
        println!("Usage:");
        println!("\t{} <options> <method1> .. <methodN> <input >output", config.exe_name);
        println!("Options:");
        println!("\t-d (to decompress)");
        println!("\t-block<N> (BWT block size)");
        println!("Passes:");
        for (name,pa) in passes.iter() {
            println!("\t{} = {}", *name, pa.info);
        }
    }else {
        output.write_le_u32(MAGIC).unwrap();
        output.write_u8(config.methods.len() as u8).unwrap();
        for met in config.methods.iter() {
            output.write_u8(met.len() as u8).unwrap();
            output.write_str(*met).unwrap();
        }
        let mut wsum: Box<Writer> = box output;
        for met in config.methods.iter() {
            match passes.find_mut(met) {
                Some(pa) => wsum = (pa.encode)(wsum, &config),
                None => fail!("Pass {} is not implemented", *met)
            }
        }
        io::util::copy(&mut input, &mut wsum).unwrap();
        wsum.flush().unwrap();
    }
}
<commit_msg>APP - fixed owned string management<commit_after>#![crate_id = "app"]
#![crate_type = "bin"]
#![deny(warnings, missing_doc)]
#![feature(macro_rules, phase)]

//! A rust-compress application that allows testing of implemented
//! algorithms and their combinations using a simple command line.
//! Example invocations:
//! echo -n "abracadabra" | ./app bwt | xxd
//! echo "banana" | ./app bwt | ./app -d

#[phase(syntax, link)] extern crate log;
extern crate compress;
extern crate collections;

use collections::HashMap;
use std::{io, os, str};
use compress::{bwt, lz4};
use compress::entropy::ari;

static MAGIC    : u32   = 0x73632172;   //=r!cs

struct Config {
    exe_name: StrBuf,
    methods: Vec<StrBuf>,
    block_size: uint,
    decompress: bool,
}

impl Config {
    fn query(args: &[StrBuf]) -> Config {
        let mut cfg = Config {
            exe_name: args[0].clone(),
            methods: Vec::new(),
            block_size: 1<<16,
            decompress: false,
        };
        let mut handlers: HashMap<&str,|&str, &mut Config|> = HashMap::new();
        handlers.insert("d",|_, cfg| { cfg.decompress = true; });
        handlers.insert("block",|b, cfg| {
            cfg.block_size = from_str(b).unwrap();
        });

        for arg in args.iter().skip(1) {
			let slice = arg.as_slice();
            if slice.starts_with("-") {
                match handlers.mut_iter().find(|&(&k,_)| slice.slice_from(1).starts_with(k)) {
                    Some((k,h)) => (*h)(slice.slice_from(1+k.len()), &mut cfg),
                    None => println!("Warning: unrecognized option: {}", arg.as_slice()),
                }
            }else {
                cfg.methods.push(arg.to_owned());
            }
        }
        cfg
    }
}

struct Pass {
    encode: |Box<Writer>, &Config|: 'static -> Box<io::Writer>,
    decode: |Box<Reader>, &Config|: 'static -> Box<io::Reader>,
    info: StrBuf,
}

/// main entry point
pub fn main() {
    let mut passes: HashMap<StrBuf,Pass> = HashMap::new();
    passes.insert("dummy".to_str(), Pass {
        encode: |w,_| w,
        decode: |r,_| r,
        info: "pass-through".to_str(),
    });
    passes.insert("ari".to_str(), Pass {
        encode: |w,_c| {
            box ari::ByteEncoder::new(w) as Box<Writer>
        },
        decode: |r,_c| {
            box ari::ByteDecoder::new(r) as Box<Reader>
        },
        info: "Adaptive arithmetic byte coder".to_str(),
    });
    passes.insert("bwt".to_str(), Pass {
        encode: |w,c| {
            box bwt::Encoder::new(w, c.block_size) as Box<Writer>
        },
        decode: |r,_c| {
            box bwt::Decoder::new(r, true) as Box<Reader>
        },
        info: "Burrows-Wheeler Transformation".to_str(),
    });
    passes.insert("mtf".to_str(), Pass {
        encode: |w,_c| {
            box bwt::mtf::Encoder::new(w) as Box<Writer>
        },
        decode: |r,_c| {
            box bwt::mtf::Decoder::new(r) as Box<Reader>
        },
        info: "Move-To-Front Transformation".to_str(),
    });
    /* // looks like we are missing the encoder implementation
    passes.insert(~"flate", Pass {
        encode: |w,_c| {
            ~flate::Encoder::new(w, true) as ~Writer
        },
        decode: |r,_c| {
            ~flate::Decoder::new(r, true) as ~Reader
        },
        info: ~"Standardized Ziv-Lempel + Huffman variant",
    });*/
    passes.insert("lz4".to_str(), Pass {
        encode: |w,_c| {
            box lz4::Encoder::new(w) as Box<Writer>
        },
        decode: |r,_c| { // LZ4 decoder seem to work
            box lz4::Decoder::new(r) as Box<Reader>
        },
        info: "Ziv-Lempel derivative, focused at speed".to_str(),
    });

    let config = Config::query(os::args().as_slice());
    let mut input = io::stdin();
    let mut output = io::stdout();
    if config.decompress {
        assert!(config.methods.is_empty(), "Decompression methods are set in stone");
        match input.read_le_u32() {
            Ok(magic) if magic != MAGIC => {
                error!("Input is not a rust-compress archive");
                return
            },
            Err(e) => {
                error!("Unable to read input: {}", e.to_str());
                return
            },
            _ => () //OK
        }
        let methods = Vec::from_fn( input.read_u8().unwrap() as uint, |_| {
            let len = input.read_u8().unwrap() as uint;
            let bytes = input.read_exact(len).unwrap();
            str::from_utf8(bytes.as_slice()).unwrap().to_owned()
        });
        let mut rsum: Box<Reader> = box input;
        for met in methods.iter() {
            info!("Found pass {}", *met);
            match passes.find_mut(met) {
                Some(pa) => rsum = (pa.decode)(rsum, &config),
                None => fail!("Pass is not implemented"),
            }
        }
        io::util::copy(&mut rsum, &mut output).unwrap();
    }else if config.methods.is_empty() {
        println!("rust-compress test application");
        println!("Usage:");
        println!("\t{} <options> <method1> .. <methodN> <input >output", config.exe_name);
        println!("Options:");
        println!("\t-d (to decompress)");
        println!("\t-block<N> (BWT block size)");
        println!("Passes:");
        for (name,pa) in passes.iter() {
            println!("\t{} = {}", *name, pa.info);
        }
    }else {
        output.write_le_u32(MAGIC).unwrap();
        output.write_u8(config.methods.len() as u8).unwrap();
        for met in config.methods.iter() {
            output.write_u8(met.len() as u8).unwrap();
            output.write_str(met.as_slice()).unwrap();
        }
        let mut wsum: Box<Writer> = box output;
        for met in config.methods.iter() {
            match passes.find_mut(met) {
                Some(pa) => wsum = (pa.encode)(wsum, &config),
                None => fail!("Pass {} is not implemented", *met)
            }
        }
        io::util::copy(&mut input, &mut wsum).unwrap();
        wsum.flush().unwrap();
    }
}
<|endoftext|>


<commit_before>use EnumMap;
use Internal;

use core::iter::Extend;
use core::hash::{Hash, Hasher};
use core::ops::{Index, IndexMut};

impl<K: Internal<V>, V> Extend<(K, V)> for EnumMap<K, V> {
    fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
        for (key, value) in iter {
            self[key] = value;
        }
    }
}

impl<'a, K, V> Extend<(&'a K, &'a V)> for EnumMap<K, V>
where
    K: Internal<V> + Copy,
    V: Copy,
{
    fn extend<I: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: I) {
        self.extend(iter.into_iter().map(|(&key, &value)| (key, value)));
    }
}

impl<K: Internal<V>, V> Index<K> for EnumMap<K, V> {
    type Output = V;

    fn index(&self, key: K) -> &V {
        &self.as_slice()[key.to_usize()]
    }
}

impl<K: Internal<V>, V> IndexMut<K> for EnumMap<K, V> {
    fn index_mut(&mut self, key: K) -> &mut V {
        &mut self.as_mut_slice()[key.to_usize()]
    }
}

// Implementations provided by derive attribute are too specific, and put requirements on K.
// This is caused by rust-lang/rust#26925.
impl<K: Internal<V>, V> Clone for EnumMap<K, V>
where
    K::Array: Clone,
{
    fn clone(&self) -> Self {
        EnumMap { array: self.array.clone() }
    }
}

impl<K: Internal<V>, V> Copy for EnumMap<K, V>
where
    K::Array: Copy,
{
}

impl<K: Internal<V>, V> PartialEq for EnumMap<K, V>
where
    K::Array: PartialEq,
{
    fn eq(&self, other: &Self) -> bool {
        self.array == other.array
    }
}

impl<K: Internal<V>, V> Eq for EnumMap<K, V>
where
    K::Array: Eq,
{
}

impl<K: Internal<V>, V> Hash for EnumMap<K, V>
where
    K::Array: Hash,
{
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.array.hash(state);
    }
}

impl<K: Internal<V>, V: Default> Default for EnumMap<K, V> {
    fn default() -> Self {
        enum_map! { _ => V::default() }
    }
}
<commit_msg>Remove K::Array: Hash bound from Hash impl<commit_after>use EnumMap;
use Internal;

use core::iter::Extend;
use core::hash::{Hash, Hasher};
use core::ops::{Index, IndexMut};

impl<K: Internal<V>, V> Extend<(K, V)> for EnumMap<K, V> {
    fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
        for (key, value) in iter {
            self[key] = value;
        }
    }
}

impl<'a, K, V> Extend<(&'a K, &'a V)> for EnumMap<K, V>
where
    K: Internal<V> + Copy,
    V: Copy,
{
    fn extend<I: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: I) {
        self.extend(iter.into_iter().map(|(&key, &value)| (key, value)));
    }
}

impl<K: Internal<V>, V> Index<K> for EnumMap<K, V> {
    type Output = V;

    fn index(&self, key: K) -> &V {
        &self.as_slice()[key.to_usize()]
    }
}

impl<K: Internal<V>, V> IndexMut<K> for EnumMap<K, V> {
    fn index_mut(&mut self, key: K) -> &mut V {
        &mut self.as_mut_slice()[key.to_usize()]
    }
}

// Implementations provided by derive attribute are too specific, and put requirements on K.
// This is caused by rust-lang/rust#26925.
impl<K: Internal<V>, V> Clone for EnumMap<K, V>
where
    K::Array: Clone,
{
    fn clone(&self) -> Self {
        EnumMap { array: self.array.clone() }
    }
}

impl<K: Internal<V>, V> Copy for EnumMap<K, V>
where
    K::Array: Copy,
{
}

impl<K: Internal<V>, V> PartialEq for EnumMap<K, V>
where
    K::Array: PartialEq,
{
    fn eq(&self, other: &Self) -> bool {
        self.array == other.array
    }
}

impl<K: Internal<V>, V> Eq for EnumMap<K, V>
where
    K::Array: Eq,
{
}

impl<K: Internal<V>, V: Hash> Hash for EnumMap<K, V> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.as_slice().hash(state);
    }
}

impl<K: Internal<V>, V: Default> Default for EnumMap<K, V> {
    fn default() -> Self {
        enum_map! { _ => V::default() }
    }
}
<|endoftext|>


<commit_before>extern crate ext4;

use std::fs;
use std::io;
use std::path;

use std::io::Read;

#[test]
fn all_types() {
    let mut files_successfully_processed = 0u64;
    for file in path::Path::new("tests/generated").read_dir().unwrap() {
        let file = file.unwrap();
        let image_name = file.file_name().into_string().unwrap();
        if !image_name.starts_with("all-types") {
            continue;
        }

        let mut img = io::BufReader::new(fs::File::open(file.path()).unwrap());
        for part in ext4::mbr::read_partition_table(&mut img).unwrap() {
            if 0x83 != part.type_code {
                continue;
            }

            let mut part_reader = ext4::mbr::read_partition(&mut img, &part).unwrap();
            let mut superblock = ext4::SuperBlock::new(&mut part_reader).unwrap();
            let root = superblock.root().unwrap();
            superblock.walk(&root, image_name.to_string(), &mut |fs, path, inode, enhanced| {
                println!("<{}> {}: {:?} {:?}", inode.number, path, enhanced, inode.stat);
                if ext4::FileType::RegularFile == inode.stat.extracted_type {
                    let expected_size = ext4::usize_check(inode.stat.size).unwrap();
                    let mut buf = Vec::with_capacity(expected_size);
                    fs.open(inode)?.read_to_end(&mut buf)?;
                    assert_eq!(expected_size, buf.len());
                }

                files_successfully_processed += 1;
                Ok(true)
            }).unwrap();

            let path = superblock.resolve_path("/home/faux/hello.txt").unwrap().inode;
            let nice_node = superblock.load_inode(path).unwrap();
            let mut s = String::new();
            superblock.open(&nice_node).unwrap().read_to_string(&mut s).unwrap();
            println!("{}", s);
        }
    }

    assert_eq!(25 * 4, files_successfully_processed);
}
<commit_msg>that test can be an assert<commit_after>extern crate ext4;

use std::fs;
use std::io;
use std::path;

use std::io::Read;

#[test]
fn all_types() {
    let mut files_successfully_processed = 0u64;
    for file in path::Path::new("tests/generated").read_dir().unwrap() {
        let file = file.unwrap();
        let image_name = file.file_name().into_string().unwrap();
        if !image_name.starts_with("all-types") {
            continue;
        }

        let mut img = io::BufReader::new(fs::File::open(file.path()).unwrap());
        for part in ext4::mbr::read_partition_table(&mut img).unwrap() {
            if 0x83 != part.type_code {
                continue;
            }

            let mut part_reader = ext4::mbr::read_partition(&mut img, &part).unwrap();
            let mut superblock = ext4::SuperBlock::new(&mut part_reader).unwrap();
            let root = superblock.root().unwrap();
            superblock.walk(&root, image_name.to_string(), &mut |fs, path, inode, enhanced| {
                println!("<{}> {}: {:?} {:?}", inode.number, path, enhanced, inode.stat);
                if ext4::FileType::RegularFile == inode.stat.extracted_type {
                    let expected_size = ext4::usize_check(inode.stat.size).unwrap();
                    let mut buf = Vec::with_capacity(expected_size);
                    fs.open(inode)?.read_to_end(&mut buf)?;
                    assert_eq!(expected_size, buf.len());
                }

                files_successfully_processed += 1;
                Ok(true)
            }).unwrap();

            let path = superblock.resolve_path("/home/faux/hello.txt").unwrap().inode;
            let nice_node = superblock.load_inode(path).unwrap();
            let mut s = String::new();
            superblock.open(&nice_node).unwrap().read_to_string(&mut s).unwrap();
            assert_eq!("Hello, world!\n", s);

        }
    }

    assert_eq!(25 * 4, files_successfully_processed);
}
<|endoftext|>