<commit_before>// Copyright 2014 Johannes Köster, Christopher Schröder.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! FASTA format reading and writing.
//!
//! # Example
//!
//! ```
//! use std::io;
//! use bio::io::fasta;
//! let reader = fasta::Reader::new(io::stdin());
//! ```

use std::io;
use std::io::prelude::*;
use std::ascii::AsciiExt;
use std::collections;
use std::fs;
use std::path::Path;
use std::convert::AsRef;

use csv;

use utils::{TextSlice, Text};

/// A FASTA reader.
pub struct Reader<R: io::Read> {
    reader: io::BufReader<R>,
    line: String,
}

impl Reader<fs::File> {
    /// Read FASTA from given file path.
    pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::open(path).map(Reader::new)
    }
}

impl<R: io::Read> Reader<R> {
    /// Create a new Fasta reader given an instance of `io::Read`.
    pub fn new(reader: R) -> Self {
        Reader {
            reader: io::BufReader::new(reader),
            line: String::new(),
        }
    }

    /// Read next FASTA record into the given `Record`.
    pub fn read(&mut self, record: &mut Record) -> io::Result<()> {
        record.clear();
        if self.line.is_empty() {
            try!(self.reader.read_line(&mut self.line));
            if self.line.is_empty() {
                return Ok(());
            }
        }

        if !self.line.starts_with('>') {
            return Err(io::Error::new(io::ErrorKind::Other, "Expected > at record start."));
        }
        record.header.push_str(&self.line);
        loop {
            self.line.clear();
            try!(self.reader.read_line(&mut self.line));
            if self.line.is_empty() || self.line.starts_with('>') {
                break;
            }
            record.seq.push_str(&self.line.trim_right());
        }

        Ok(())
    }

    /// Return an iterator over the records of this FastQ file.
    pub fn records(self) -> Records<R> {
        Records { reader: self }
    }
}

/// A FASTA index as created by SAMtools (.fai).
pub struct Index {
    inner: collections::HashMap<String, IndexRecord>,
    seqs: Vec<String>,
}

impl Index {
    /// Open a FASTA index from a given `io::Read` instance.
    pub fn new<R: io::Read>(fai: R) -> csv::Result<Self> {
        let mut inner = collections::HashMap::new();
        let mut seqs = vec![];
        let mut fai_reader = csv::Reader::from_reader(fai).delimiter(b'\t').has_headers(false);
        for row in fai_reader.decode() {
            let (name, record): (String, IndexRecord) = try!(row);
            seqs.push(name.clone());
            inner.insert(name, record);
        }
        Ok(Index {
            inner: inner,
            seqs: seqs,
        })
    }

    /// Open a FASTA index from a given file path.
    pub fn from_file<P: AsRef<Path>>(path: &P) -> csv::Result<Self> {
        match fs::File::open(path) {
            Ok(fai) => Self::new(fai),
            Err(e) => Err(csv::Error::Io(e)),
        }
    }

    /// Open a FASTA index given the corresponding FASTA file path (e.g. for ref.fasta we expect ref.fasta.fai).
    pub fn with_fasta_file<P: AsRef<Path>>(fasta_path: &P) -> csv::Result<Self> {
        let mut ext = fasta_path.as_ref().extension().unwrap().to_str().unwrap().to_owned();
        ext.push_str(".fai");
        let fai_path = fasta_path.as_ref().with_extension(ext);

        Self::from_file(&fai_path)
    }

    /// Return a vector of sequences described in the index.
    pub fn sequences(&self) -> Vec<Sequence> {
        self.seqs
            .iter()
            .map(|name| {
                Sequence {
                    name: name.clone(),
                    len: self.inner.get(name).unwrap().len,
                }
            })
            .collect()
    }
}

/// A FASTA reader with an index as created by SAMtools (.fai).
pub struct IndexedReader<R: io::Read + io::Seek> {
    reader: io::BufReader<R>,
    pub index: Index,
}

impl IndexedReader<fs::File> {
    /// Read from a given file path. This assumes the index ref.fasta.fai to be present for FASTA ref.fasta.
    pub fn from_file<P: AsRef<Path>>(path: &P) -> csv::Result<Self> {
        let index = try!(Index::with_fasta_file(path));

        match fs::File::open(path) {
            Ok(fasta) => Ok(IndexedReader::with_index(fasta, index)),
            Err(e) => Err(csv::Error::Io(e)),
        }
    }
}

impl<R: io::Read + io::Seek> IndexedReader<R> {
    /// Read from a FASTA and its index, both given as `io::Read`. FASTA has to be `io::Seek` in addition.
    pub fn new<I: io::Read>(fasta: R, fai: I) -> csv::Result<Self> {
        let index = try!(Index::new(fai));
        Ok(IndexedReader {
            reader: io::BufReader::new(fasta),
            index: index,
        })
    }

    /// Read from a FASTA and its index, the first given as `io::Read`, the second given as index object.
    pub fn with_index(fasta: R, index: Index) -> Self {
        IndexedReader {
            reader: io::BufReader::new(fasta),
            index: index,
        }
    }

    /// For a given seqname, read the whole sequence into the given vector.
    pub fn read_all(&mut self, seqname: &str, seq: &mut Text) -> io::Result<()> {
        match self.index.inner.get(seqname) {
            Some(&idx) => self.read(seqname, 0, idx.len, seq),
            None => Err(io::Error::new(io::ErrorKind::Other, "Unknown sequence name.")),
        }
    }

    /// Read the given interval of the given seqname into the given vector (stop position is exclusive).
    pub fn read(&mut self,
                seqname: &str,
                start: u64,
                stop: u64,
                seq: &mut Text)
                -> io::Result<()> {
        match self.index.inner.get(seqname) {
            Some(idx) => {
                seq.clear();
                // derived from
                // http://www.allenyu.info/item/24-quickly-fetch-sequence-from-samtools-faidx-indexed-fasta-sequences.html
                let line = start / idx.line_bases * idx.line_bytes;
                let line_offset = start % idx.line_bases;
                let offset = idx.offset + line + line_offset;
                let lines = stop / idx.line_bases * idx.line_bytes - line;
                let line_stop = stop % idx.line_bases -
                                if lines == 0 {
                    line_offset
                } else {
                    0
                };

                try!(self.reader.seek(io::SeekFrom::Start(offset)));
                let mut buf = vec![0u8; idx.line_bases as usize];
                for _ in 0..lines {
                    // read full lines
                    try!(self.reader.read(&mut buf));
                    seq.extend_from_slice(&buf);
                }
                // read last line
                println!("linestop {}", line_stop);
                try!(self.reader.read(&mut buf[..line_stop as usize]));
                seq.extend_from_slice(&buf[..line_stop as usize]);
                Ok(())
            }
            None => Err(io::Error::new(io::ErrorKind::Other, "Unknown sequence name.")),
        }
    }
}

/// Record of a FASTA index.
#[derive(RustcDecodable, Debug, Copy, Clone)]
struct IndexRecord {
    len: u64,
    offset: u64,
    line_bases: u64,
    line_bytes: u64,
}

/// A sequence record returned by the FASTA index.
pub struct Sequence {
    pub name: String,
    pub len: u64,
}

/// A Fasta writer.
pub struct Writer<W: io::Write> {
    writer: io::BufWriter<W>,
}

impl Writer<fs::File> {
    /// Write to the given file path.
    pub fn to_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::create(path).map(Writer::new)
    }
}

impl<W: io::Write> Writer<W> {
    /// Create a new Fasta writer.
    pub fn new(writer: W) -> Self {
        Writer { writer: io::BufWriter::new(writer) }
    }

    /// Directly write a Fasta record.
    pub fn write_record(&mut self, record: Record) -> io::Result<()> {
        self.write(record.id().unwrap_or(""), record.desc(), record.seq())
    }

    /// Write a Fasta record with given id, optional description and sequence.
    pub fn write(&mut self, id: &str, desc: Option<&str>, seq: TextSlice) -> io::Result<()> {
        try!(self.writer.write(b">"));
        try!(self.writer.write(id.as_bytes()));
        if desc.is_some() {
            try!(self.writer.write(b" "));
            try!(self.writer.write(desc.unwrap().as_bytes()));
        }
        try!(self.writer.write(b"\n"));
        try!(self.writer.write(seq));
        try!(self.writer.write(b"\n"));

        Ok(())
    }

    /// Flush the writer, ensuring that everything is written.
    pub fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

/// A FASTA record.
pub struct Record {
    header: String,
    seq: String,
}

impl Record {
    /// Create a new instance.
    pub fn new() -> Self {
        Record {
            header: String::new(),
            seq: String::new(),
        }
    }

    /// Check if record is empty.
    pub fn is_empty(&self) -> bool {
        self.header.is_empty() && self.seq.is_empty()
    }

    /// Check validity of Fasta record.
    pub fn check(&self) -> Result<(), &str> {
        if self.id().is_none() {
            return Err("Expecting id for FastQ record.");
        }
        if !self.seq.is_ascii() {
            return Err("Non-ascii character found in sequence.");
        }

        Ok(())
    }

    /// Return the id of the record.
    pub fn id(&self) -> Option<&str> {
        self.header[1..].trim_right().splitn(2, ' ').next()
    }

    /// Return descriptions if present.
    pub fn desc(&self) -> Option<&str> {
        self.header[1..].trim_right().splitn(2, ' ').skip(1).next()
    }

    /// Return the sequence of the record.
    pub fn seq(&self) -> TextSlice {
        self.seq.as_bytes()
    }

    /// Clear the record.
    fn clear(&mut self) {
        self.header.clear();
        self.seq.clear();
    }
}

/// An iterator over the records of a Fasta file.
pub struct Records<R: io::Read> {
    reader: Reader<R>,
}

impl<R: io::Read> Iterator for Records<R> {
    type Item = io::Result<Record>;

    fn next(&mut self) -> Option<io::Result<Record>> {
        let mut record = Record::new();
        match self.reader.read(&mut record) {
            Ok(()) if record.is_empty() => None,
            Ok(()) => Some(Ok(record)),
            Err(err) => Some(Err(err)),
        }
    }
}

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

    const FASTA_FILE: &'static [u8] = b">id desc
ACCGTAGGCTGA
>id2
ATTGTTGTTTTA
";
    const FAI_FILE: &'static [u8] = b"id\t12\t9\t60\t61
";

    #[test]
    fn test_reader() {
        let reader = Reader::new(FASTA_FILE);
        let ids = [Some("id"), Some("id2")];
        let descs = [Some("desc"), None];
        let seqs: [&[u8]; 2] = [b"ACCGTAGGCTGA", b"ATTGTTGTTTTA"];

        for (i, r) in reader.records().enumerate() {
            let record = r.ok().expect("Error reading record");
            assert_eq!(record.check(), Ok(()));
            assert_eq!(record.id(), ids[i]);
            assert_eq!(record.desc(), descs[i]);
            assert_eq!(record.seq(), seqs[i]);
        }

        // let record = records.ok().nth(1).unwrap();
    }

    #[test]
    fn test_indexed_reader() {
        let mut reader = IndexedReader::new(io::Cursor::new(FASTA_FILE), FAI_FILE)
                             .ok()
                             .expect("Error reading index");
        let mut seq = Vec::new();
        reader.read(b"id", 1, 5, &mut seq).ok().expect("Error reading sequence.");
        assert_eq!(seq, b"CCGT");
    }

    #[test]
    fn test_writer() {
        let mut writer = Writer::new(Vec::new());
        writer.write("id", Some("desc"), b"ACCGTAGGCTGA").ok().expect("Expected successful write");
        writer.write("id2", None, b"ATTGTTGTTTTA").ok().expect("Expected successful write");
        writer.flush().ok().expect("Expected successful write");
        assert_eq!(writer.writer.get_ref(), &FASTA_FILE);
    }
}
<commit_msg>Fixed test case.<commit_after>// Copyright 2014 Johannes Köster, Christopher Schröder.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! FASTA format reading and writing.
//!
//! # Example
//!
//! ```
//! use std::io;
//! use bio::io::fasta;
//! let reader = fasta::Reader::new(io::stdin());
//! ```

use std::io;
use std::io::prelude::*;
use std::ascii::AsciiExt;
use std::collections;
use std::fs;
use std::path::Path;
use std::convert::AsRef;

use csv;

use utils::{TextSlice, Text};

/// A FASTA reader.
pub struct Reader<R: io::Read> {
    reader: io::BufReader<R>,
    line: String,
}

impl Reader<fs::File> {
    /// Read FASTA from given file path.
    pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::open(path).map(Reader::new)
    }
}

impl<R: io::Read> Reader<R> {
    /// Create a new Fasta reader given an instance of `io::Read`.
    pub fn new(reader: R) -> Self {
        Reader {
            reader: io::BufReader::new(reader),
            line: String::new(),
        }
    }

    /// Read next FASTA record into the given `Record`.
    pub fn read(&mut self, record: &mut Record) -> io::Result<()> {
        record.clear();
        if self.line.is_empty() {
            try!(self.reader.read_line(&mut self.line));
            if self.line.is_empty() {
                return Ok(());
            }
        }

        if !self.line.starts_with('>') {
            return Err(io::Error::new(io::ErrorKind::Other, "Expected > at record start."));
        }
        record.header.push_str(&self.line);
        loop {
            self.line.clear();
            try!(self.reader.read_line(&mut self.line));
            if self.line.is_empty() || self.line.starts_with('>') {
                break;
            }
            record.seq.push_str(&self.line.trim_right());
        }

        Ok(())
    }

    /// Return an iterator over the records of this FastQ file.
    pub fn records(self) -> Records<R> {
        Records { reader: self }
    }
}

/// A FASTA index as created by SAMtools (.fai).
pub struct Index {
    inner: collections::HashMap<String, IndexRecord>,
    seqs: Vec<String>,
}

impl Index {
    /// Open a FASTA index from a given `io::Read` instance.
    pub fn new<R: io::Read>(fai: R) -> csv::Result<Self> {
        let mut inner = collections::HashMap::new();
        let mut seqs = vec![];
        let mut fai_reader = csv::Reader::from_reader(fai).delimiter(b'\t').has_headers(false);
        for row in fai_reader.decode() {
            let (name, record): (String, IndexRecord) = try!(row);
            seqs.push(name.clone());
            inner.insert(name, record);
        }
        Ok(Index {
            inner: inner,
            seqs: seqs,
        })
    }

    /// Open a FASTA index from a given file path.
    pub fn from_file<P: AsRef<Path>>(path: &P) -> csv::Result<Self> {
        match fs::File::open(path) {
            Ok(fai) => Self::new(fai),
            Err(e) => Err(csv::Error::Io(e)),
        }
    }

    /// Open a FASTA index given the corresponding FASTA file path (e.g. for ref.fasta we expect ref.fasta.fai).
    pub fn with_fasta_file<P: AsRef<Path>>(fasta_path: &P) -> csv::Result<Self> {
        let mut ext = fasta_path.as_ref().extension().unwrap().to_str().unwrap().to_owned();
        ext.push_str(".fai");
        let fai_path = fasta_path.as_ref().with_extension(ext);

        Self::from_file(&fai_path)
    }

    /// Return a vector of sequences described in the index.
    pub fn sequences(&self) -> Vec<Sequence> {
        self.seqs
            .iter()
            .map(|name| {
                Sequence {
                    name: name.clone(),
                    len: self.inner.get(name).unwrap().len,
                }
            })
            .collect()
    }
}

/// A FASTA reader with an index as created by SAMtools (.fai).
pub struct IndexedReader<R: io::Read + io::Seek> {
    reader: io::BufReader<R>,
    pub index: Index,
}

impl IndexedReader<fs::File> {
    /// Read from a given file path. This assumes the index ref.fasta.fai to be present for FASTA ref.fasta.
    pub fn from_file<P: AsRef<Path>>(path: &P) -> csv::Result<Self> {
        let index = try!(Index::with_fasta_file(path));

        match fs::File::open(path) {
            Ok(fasta) => Ok(IndexedReader::with_index(fasta, index)),
            Err(e) => Err(csv::Error::Io(e)),
        }
    }
}

impl<R: io::Read + io::Seek> IndexedReader<R> {
    /// Read from a FASTA and its index, both given as `io::Read`. FASTA has to be `io::Seek` in addition.
    pub fn new<I: io::Read>(fasta: R, fai: I) -> csv::Result<Self> {
        let index = try!(Index::new(fai));
        Ok(IndexedReader {
            reader: io::BufReader::new(fasta),
            index: index,
        })
    }

    /// Read from a FASTA and its index, the first given as `io::Read`, the second given as index object.
    pub fn with_index(fasta: R, index: Index) -> Self {
        IndexedReader {
            reader: io::BufReader::new(fasta),
            index: index,
        }
    }

    /// For a given seqname, read the whole sequence into the given vector.
    pub fn read_all(&mut self, seqname: &str, seq: &mut Text) -> io::Result<()> {
        match self.index.inner.get(seqname) {
            Some(&idx) => self.read(seqname, 0, idx.len, seq),
            None => Err(io::Error::new(io::ErrorKind::Other, "Unknown sequence name.")),
        }
    }

    /// Read the given interval of the given seqname into the given vector (stop position is exclusive).
    pub fn read(&mut self,
                seqname: &str,
                start: u64,
                stop: u64,
                seq: &mut Text)
                -> io::Result<()> {
        match self.index.inner.get(seqname) {
            Some(idx) => {
                seq.clear();
                // derived from
                // http://www.allenyu.info/item/24-quickly-fetch-sequence-from-samtools-faidx-indexed-fasta-sequences.html
                let line = start / idx.line_bases * idx.line_bytes;
                let line_offset = start % idx.line_bases;
                let offset = idx.offset + line + line_offset;
                let lines = stop / idx.line_bases * idx.line_bytes - line;
                let line_stop = stop % idx.line_bases -
                                if lines == 0 {
                    line_offset
                } else {
                    0
                };

                try!(self.reader.seek(io::SeekFrom::Start(offset)));
                let mut buf = vec![0u8; idx.line_bases as usize];
                for _ in 0..lines {
                    // read full lines
                    try!(self.reader.read(&mut buf));
                    seq.extend_from_slice(&buf);
                }
                // read last line
                println!("linestop {}", line_stop);
                try!(self.reader.read(&mut buf[..line_stop as usize]));
                seq.extend_from_slice(&buf[..line_stop as usize]);
                Ok(())
            }
            None => Err(io::Error::new(io::ErrorKind::Other, "Unknown sequence name.")),
        }
    }
}

/// Record of a FASTA index.
#[derive(RustcDecodable, Debug, Copy, Clone)]
struct IndexRecord {
    len: u64,
    offset: u64,
    line_bases: u64,
    line_bytes: u64,
}

/// A sequence record returned by the FASTA index.
pub struct Sequence {
    pub name: String,
    pub len: u64,
}

/// A Fasta writer.
pub struct Writer<W: io::Write> {
    writer: io::BufWriter<W>,
}

impl Writer<fs::File> {
    /// Write to the given file path.
    pub fn to_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::create(path).map(Writer::new)
    }
}

impl<W: io::Write> Writer<W> {
    /// Create a new Fasta writer.
    pub fn new(writer: W) -> Self {
        Writer { writer: io::BufWriter::new(writer) }
    }

    /// Directly write a Fasta record.
    pub fn write_record(&mut self, record: Record) -> io::Result<()> {
        self.write(record.id().unwrap_or(""), record.desc(), record.seq())
    }

    /// Write a Fasta record with given id, optional description and sequence.
    pub fn write(&mut self, id: &str, desc: Option<&str>, seq: TextSlice) -> io::Result<()> {
        try!(self.writer.write(b">"));
        try!(self.writer.write(id.as_bytes()));
        if desc.is_some() {
            try!(self.writer.write(b" "));
            try!(self.writer.write(desc.unwrap().as_bytes()));
        }
        try!(self.writer.write(b"\n"));
        try!(self.writer.write(seq));
        try!(self.writer.write(b"\n"));

        Ok(())
    }

    /// Flush the writer, ensuring that everything is written.
    pub fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

/// A FASTA record.
pub struct Record {
    header: String,
    seq: String,
}

impl Record {
    /// Create a new instance.
    pub fn new() -> Self {
        Record {
            header: String::new(),
            seq: String::new(),
        }
    }

    /// Check if record is empty.
    pub fn is_empty(&self) -> bool {
        self.header.is_empty() && self.seq.is_empty()
    }

    /// Check validity of Fasta record.
    pub fn check(&self) -> Result<(), &str> {
        if self.id().is_none() {
            return Err("Expecting id for FastQ record.");
        }
        if !self.seq.is_ascii() {
            return Err("Non-ascii character found in sequence.");
        }

        Ok(())
    }

    /// Return the id of the record.
    pub fn id(&self) -> Option<&str> {
        self.header[1..].trim_right().splitn(2, ' ').next()
    }

    /// Return descriptions if present.
    pub fn desc(&self) -> Option<&str> {
        self.header[1..].trim_right().splitn(2, ' ').skip(1).next()
    }

    /// Return the sequence of the record.
    pub fn seq(&self) -> TextSlice {
        self.seq.as_bytes()
    }

    /// Clear the record.
    fn clear(&mut self) {
        self.header.clear();
        self.seq.clear();
    }
}

/// An iterator over the records of a Fasta file.
pub struct Records<R: io::Read> {
    reader: Reader<R>,
}

impl<R: io::Read> Iterator for Records<R> {
    type Item = io::Result<Record>;

    fn next(&mut self) -> Option<io::Result<Record>> {
        let mut record = Record::new();
        match self.reader.read(&mut record) {
            Ok(()) if record.is_empty() => None,
            Ok(()) => Some(Ok(record)),
            Err(err) => Some(Err(err)),
        }
    }
}

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

    const FASTA_FILE: &'static [u8] = b">id desc
ACCGTAGGCTGA
>id2
ATTGTTGTTTTA
";
    const FAI_FILE: &'static [u8] = b"id\t12\t9\t60\t61
";

    #[test]
    fn test_reader() {
        let reader = Reader::new(FASTA_FILE);
        let ids = [Some("id"), Some("id2")];
        let descs = [Some("desc"), None];
        let seqs: [&[u8]; 2] = [b"ACCGTAGGCTGA", b"ATTGTTGTTTTA"];

        for (i, r) in reader.records().enumerate() {
            let record = r.ok().expect("Error reading record");
            assert_eq!(record.check(), Ok(()));
            assert_eq!(record.id(), ids[i]);
            assert_eq!(record.desc(), descs[i]);
            assert_eq!(record.seq(), seqs[i]);
        }

        // let record = records.ok().nth(1).unwrap();
    }

    #[test]
    fn test_indexed_reader() {
        let mut reader = IndexedReader::new(io::Cursor::new(FASTA_FILE), FAI_FILE)
                             .ok()
                             .expect("Error reading index");
        let mut seq = Vec::new();
        reader.read("id", 1, 5, &mut seq).ok().expect("Error reading sequence.");
        assert_eq!(seq, b"CCGT");
    }

    #[test]
    fn test_writer() {
        let mut writer = Writer::new(Vec::new());
        writer.write("id", Some("desc"), b"ACCGTAGGCTGA").ok().expect("Expected successful write");
        writer.write("id2", None, b"ATTGTTGTTTTA").ok().expect("Expected successful write");
        writer.flush().ok().expect("Expected successful write");
        assert_eq!(writer.writer.get_ref(), &FASTA_FILE);
    }
}
<|endoftext|>


<commit_before>use gl;
use glfw::{self, Action, Context, CursorMode, Key, MouseButton, SwapInterval, Window};
use std::cell::RefCell;
use std::os::raw::c_void;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
use time::{Duration, SteadyTime};

use camera::{Camera, Freefly};
use transform::Translation;

/// Dimension of the window to create.
#[derive(Clone, Copy, Debug)]
pub enum WindowDim {
  Windowed(u32, u32),
  FullScreen,
  FullScreenRestricted(u32, u32)
}

type Keyboard = mpsc::Receiver<(Key, Action)>;
type Mouse = mpsc::Receiver<(MouseButton, Action)>;
type MouseMove = mpsc::Receiver<[f64; 2]>;
type Scroll = mpsc::Receiver<[f64; 2]>;

/// Empty handler.
///
/// This handler will just let pass all events without doing anything. It’s only useful for debug
/// purposes when you don’t want to bother with interaction – it doesn’t even let you close the
/// application!
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Unhandled;

/// Class of event handlers.
pub trait EventHandler {
  /// Implement this function if you want to react to key strokes.
  fn on_key(&mut self, _: Key, _: Action) -> bool { true }
  /// Implement this function if you want to react to mouse button events.
  fn on_mouse_button(&mut self, _: MouseButton, _: Action) -> bool { true }
  /// Implement this function if you want to react to cursor moves.
  fn on_cursor_move(&mut self, _: [f64; 2]) -> bool { true }
  /// Implement this function if you want to react to scroll events.
  fn on_scroll(&mut self, _: [f64; 2]) -> bool { true }
}

impl EventHandler for Unhandled {}

/// Device object.
///
/// Upon bootstrapping, this type is created to add interaction and context handling.
pub struct Device {
  /// Width of the window.
  w: u32,
  /// Height of the window.
  h: u32,
  /// Some kind of epoch start the application started at.
  start_time: SteadyTime,
  /// Keyboard receiver.
  kbd: Keyboard,
  /// Mouse receiver.
  mouse: Mouse,
  /// Cursor receiver.
  cursor: MouseMove,
  /// Scroll receiver.
  scroll: Scroll,
  /// Window.
  window: Window,
  /// Event thread join handle. Unused and keep around until death.
  #[allow(dead_code)]
  event_thread: thread::JoinHandle<()>
}

impl Device {
  /// Entry point.
  ///
  /// This function is the first one you have to call before anything else related to this crate.
  ///
  /// # Arguments
  ///
  /// - `dim`: dimension of the window to create
  /// - `title`: title to give to the window
  pub fn bootstrap(dim: WindowDim, title: &'static str) -> Self {
    info!("{} starting", title);
    info!("window mode: {:?}", dim);

    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    // OpenGL hints
    glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
    glfw.window_hint(glfw::WindowHint::ContextVersionMajor(3));
    glfw.window_hint(glfw::WindowHint::ContextVersionMinor(3));

    // open a window in windowed or fullscreen mode
    let (mut window, events, w, h) = match dim {
      WindowDim::Windowed(w, h) => {
        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Windowed).expect("Failed to create GLFW window.");
        (window, events, w, h)
      },
      WindowDim::FullScreen => {
        glfw.with_primary_monitor(|glfw, monitor| {
          let monitor = monitor.unwrap();
          let vmode = monitor.get_video_mode().expect("primary monitor’s video mode");
          let (w, h) = (vmode.width, vmode.height);

          let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
          (window, events, w, h)
        })
      },
      WindowDim::FullScreenRestricted(w, h) => {
        glfw.with_primary_monitor(|glfw, monitor| {
          let monitor = monitor.unwrap();

          let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
          (window, events, w, h)
        })
      }
    };

    deb!("opened window");

    window.make_current();

    // FIXME: use a target instead
    if cfg!(feature = "release") {
      deb!("hiding cursor");
      window.set_cursor_mode(CursorMode::Disabled);
    }

    window.set_key_polling(true);
    window.set_cursor_pos_polling(true);
    window.set_mouse_button_polling(true);
    window.set_scroll_polling(true);
    glfw.set_swap_interval(SwapInterval::Sync(1));

    deb!("initializing OpenGL pointers");

    // init OpenGL
    gl::load_with(|s| window.get_proc_address(s) as *const c_void);

    // create channels to stream keyboard and mouse events
    let (kbd_snd, kbd_rcv) = mpsc::channel();
    let (mouse_snd, mouse_rcv) = mpsc::channel();
    let (cursor_snd, cursor_rcv) = mpsc::channel();
    let (scroll_snd, scroll_rcv) = mpsc::channel();

    deb!("spawning the event thread");
    let event_thread = thread::spawn(move || {
      loop {
        glfw.wait_events();

        for (_, event) in glfw::flush_messages(&events) {
          match event {
            glfw::WindowEvent::Key(key, _, action, _) => {
              let _ = kbd_snd.send((key, action));
            },
            glfw::WindowEvent::MouseButton(button, action, _) => {
              let _ = mouse_snd.send((button, action));
            },
            glfw::WindowEvent::CursorPos(x, y) => {
              let _ = cursor_snd.send([x, y]);
            },
            glfw::WindowEvent::Scroll(x, y) => {
              let _ = scroll_snd.send([x, y]);
            },
            _ => {},
          }
        }
      }
    });

    deb!("bootstrapping finished");

    Device {
      w: w,
      h: h,
      start_time: SteadyTime::now(),
      kbd: kbd_rcv,
      mouse: mouse_rcv,
      cursor: cursor_rcv,
      scroll: scroll_rcv,
      window: window,
      event_thread: event_thread
    }
  }

  /// Width of the attached window.
  #[inline]
  pub fn width(&self) -> u32 {
    self.w
  }

  /// Height of the attached window.
  #[inline]
  pub fn height(&self) -> u32 {
    self.h
  }

  /// Current time, starting from the beginning of the creation of that object.
  pub fn time(&self) -> f64 {
    (SteadyTime::now() - self.start_time).num_nanoseconds().unwrap() as f64 * 1e-9
  }

  /// Dispatch events to a handler.
  pub fn dispatch_events<H>(&self, handler: &mut H) -> bool where H: EventHandler {
    while let Ok((key, action)) = self.kbd.try_recv() {
      if !handler.on_key(key, action) {
        return false;
      }
    }

    while let Ok((button, action)) = self.mouse.try_recv() {
      if !handler.on_mouse_button(button, action) {
        return false;
      }
    }

    while let Ok(xy) = self.cursor.try_recv() {
      if !handler.on_cursor_move(xy) {
        return false;
      }
    }

    while let Ok(xy) = self.scroll.try_recv() {
      if !handler.on_scroll(xy) {
        return false;
      }
    }

    true
  }

  /// Step function.
  ///
  /// This function provides two features:
  ///
  /// - it runs a *drawer* function, responsible of rendering a single frame, by passing it the
  ///   current time
  /// - it performs process idleing if you have requested a certain *framerate* – frame per second.
  ///
  /// The second feature is very neat because it lets you handle the scheduler off your application
  /// and then contribute to better CPU usage.
  ///
  /// > Note: if you pass `None`, no idleing will take place. However, you might be blocked by the
  /// *VSync* if enabled in your driver.
  pub fn step<FPS, R>(&mut self, fps: FPS, mut draw_frame: R) -> bool where FPS: Into<Option<u32>>, R: FnMut(f64) {
    let loop_start_time = SteadyTime::now();

    if self.window.should_close() {
      return false;
    }

    let t = self.time();

    draw_frame(t);

    self.window.swap_buffers();

    // wait for next frame according to the wished FPS
    if let Some(fps) = fps.into() {
      let fps = fps as f32;
      let elapsed_time = SteadyTime::now() - loop_start_time;
      let max_time = Duration::nanoseconds((1. / (fps as f64) * 1e9) as i64);

      if elapsed_time > max_time {
        let sleep_time = max_time - elapsed_time;
        thread::sleep(sleep_time.to_std().unwrap());
      }
    }

    true
  }
}

/// Freefly handler.
///
/// This handler is very neat as it provides freefly interaction.
pub struct FreeflyHandler {
  camera: Rc<RefCell<Camera<Freefly>>>,
  left_down: bool,
  right_down: bool,
  last_cursor: [f64; 2]
}

impl FreeflyHandler {
  pub fn new(camera: Rc<RefCell<Camera<Freefly>>>) -> Self {
    FreeflyHandler {
      camera: camera,
      left_down: false,
      right_down: false,
      last_cursor: [0., 0.]
    }
  }

  fn move_camera_on_event(&mut self, key: Key) {
    let camera = &mut self.camera.borrow_mut();

    match key {
      Key::W => camera.mv(Translation::new(0., 0., 1.)),
      Key::S => camera.mv(Translation::new(0., 0., -1.)),
      Key::A => camera.mv(Translation::new(1., 0., 0.)),
      Key::D => camera.mv(Translation::new(-1., 0., 0.)),
      Key::Q => camera.mv(Translation::new(0., -1., 0.)),
      Key::E => camera.mv(Translation::new(0., 1., 0.)),
      _ => ()
    }
  }

  fn orient_camera_on_event(&mut self, cursor: [f64; 2]) {
    let camera = &mut self.camera.borrow_mut();

    if self.left_down {
      let (dx, dy) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(dy as f32, dx as f32, 0.));
    } else if self.right_down {
      let (dx, _) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(0., 0., dx as f32));
    }

    self.last_cursor = cursor;
  }
}

impl EventHandler for FreeflyHandler {
  fn on_key(&mut self, key: Key, action: Action) -> bool {
    match action {
      Action::Press | Action::Repeat => self.move_camera_on_event(key),
      Action::Release => if key == Key::Escape { return false }
    }

    true
  }

  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> bool {
    match (button, action) {
      (MouseButton::Button1, Action::Press) => {
        self.left_down = true;
      },
      (MouseButton::Button1, Action::Release) => {
        self.left_down = false;
      },
      (MouseButton::Button2, Action::Press) => {
        self.right_down = true;
      },
      (MouseButton::Button2, Action::Release) => {
        self.right_down = false;
      },
      _ => ()
    }

    true
  }

  fn on_cursor_move(&mut self, dir: [f64; 2]) -> bool {
    self.orient_camera_on_event(dir);
    true
  }
}
<commit_msg>Using std::time::{Duration, Instant} instead of time::*.<commit_after>use gl;
use glfw::{self, Action, Context, CursorMode, Key, MouseButton, SwapInterval, Window};
use std::cell::RefCell;
use std::os::raw::c_void;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
use std::time::{Duration, Instant};

use camera::{Camera, Freefly};
use transform::Translation;

/// Dimension of the window to create.
#[derive(Clone, Copy, Debug)]
pub enum WindowDim {
  Windowed(u32, u32),
  FullScreen,
  FullScreenRestricted(u32, u32)
}

type Keyboard = mpsc::Receiver<(Key, Action)>;
type Mouse = mpsc::Receiver<(MouseButton, Action)>;
type MouseMove = mpsc::Receiver<[f64; 2]>;
type Scroll = mpsc::Receiver<[f64; 2]>;

/// Empty handler.
///
/// This handler will just let pass all events without doing anything. It’s only useful for debug
/// purposes when you don’t want to bother with interaction – it doesn’t even let you close the
/// application!
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Unhandled;

/// Class of event handlers.
pub trait EventHandler {
  /// Implement this function if you want to react to key strokes.
  fn on_key(&mut self, _: Key, _: Action) -> bool { true }
  /// Implement this function if you want to react to mouse button events.
  fn on_mouse_button(&mut self, _: MouseButton, _: Action) -> bool { true }
  /// Implement this function if you want to react to cursor moves.
  fn on_cursor_move(&mut self, _: [f64; 2]) -> bool { true }
  /// Implement this function if you want to react to scroll events.
  fn on_scroll(&mut self, _: [f64; 2]) -> bool { true }
}

impl EventHandler for Unhandled {}

/// Device object.
///
/// Upon bootstrapping, this type is created to add interaction and context handling.
pub struct Device {
  /// Width of the window.
  w: u32,
  /// Height of the window.
  h: u32,
  /// Some kind of epoch start the application started at.
  start_time: Instant,
  /// Keyboard receiver.
  kbd: Keyboard,
  /// Mouse receiver.
  mouse: Mouse,
  /// Cursor receiver.
  cursor: MouseMove,
  /// Scroll receiver.
  scroll: Scroll,
  /// Window.
  window: Window,
  /// Event thread join handle. Unused and keep around until death.
  #[allow(dead_code)]
  event_thread: thread::JoinHandle<()>
}

impl Device {
  /// Entry point.
  ///
  /// This function is the first one you have to call before anything else related to this crate.
  ///
  /// # Arguments
  ///
  /// - `dim`: dimension of the window to create
  /// - `title`: title to give to the window
  pub fn bootstrap(dim: WindowDim, title: &'static str) -> Self {
    info!("{} starting", title);
    info!("window mode: {:?}", dim);

    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    // OpenGL hints
    glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
    glfw.window_hint(glfw::WindowHint::ContextVersionMajor(3));
    glfw.window_hint(glfw::WindowHint::ContextVersionMinor(3));

    // open a window in windowed or fullscreen mode
    let (mut window, events, w, h) = match dim {
      WindowDim::Windowed(w, h) => {
        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Windowed).expect("Failed to create GLFW window.");
        (window, events, w, h)
      },
      WindowDim::FullScreen => {
        glfw.with_primary_monitor(|glfw, monitor| {
          let monitor = monitor.unwrap();
          let vmode = monitor.get_video_mode().expect("primary monitor’s video mode");
          let (w, h) = (vmode.width, vmode.height);

          let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
          (window, events, w, h)
        })
      },
      WindowDim::FullScreenRestricted(w, h) => {
        glfw.with_primary_monitor(|glfw, monitor| {
          let monitor = monitor.unwrap();

          let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
          (window, events, w, h)
        })
      }
    };

    deb!("opened window");

    window.make_current();

    // FIXME: use a target instead
    if cfg!(feature = "release") {
      deb!("hiding cursor");
      window.set_cursor_mode(CursorMode::Disabled);
    }

    window.set_key_polling(true);
    window.set_cursor_pos_polling(true);
    window.set_mouse_button_polling(true);
    window.set_scroll_polling(true);
    glfw.set_swap_interval(SwapInterval::Sync(1));

    deb!("initializing OpenGL pointers");

    // init OpenGL
    gl::load_with(|s| window.get_proc_address(s) as *const c_void);

    // create channels to stream keyboard and mouse events
    let (kbd_snd, kbd_rcv) = mpsc::channel();
    let (mouse_snd, mouse_rcv) = mpsc::channel();
    let (cursor_snd, cursor_rcv) = mpsc::channel();
    let (scroll_snd, scroll_rcv) = mpsc::channel();

    deb!("spawning the event thread");
    let event_thread = thread::spawn(move || {
      loop {
        glfw.wait_events();

        for (_, event) in glfw::flush_messages(&events) {
          match event {
            glfw::WindowEvent::Key(key, _, action, _) => {
              let _ = kbd_snd.send((key, action));
            },
            glfw::WindowEvent::MouseButton(button, action, _) => {
              let _ = mouse_snd.send((button, action));
            },
            glfw::WindowEvent::CursorPos(x, y) => {
              let _ = cursor_snd.send([x, y]);
            },
            glfw::WindowEvent::Scroll(x, y) => {
              let _ = scroll_snd.send([x, y]);
            },
            _ => {},
          }
        }
      }
    });

    deb!("bootstrapping finished");

    Device {
      w: w,
      h: h,
      start_time: Instant::now(),
      kbd: kbd_rcv,
      mouse: mouse_rcv,
      cursor: cursor_rcv,
      scroll: scroll_rcv,
      window: window,
      event_thread: event_thread
    }
  }

  /// Width of the attached window.
  #[inline]
  pub fn width(&self) -> u32 {
    self.w
  }

  /// Height of the attached window.
  #[inline]
  pub fn height(&self) -> u32 {
    self.h
  }

  /// Current time, starting from the beginning of the creation of that object.
  pub fn time(&self) -> f64 {
    let elapsed = Instant::now() - self.start_time;
    elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9
  }

  /// Dispatch events to a handler.
  pub fn dispatch_events<H>(&self, handler: &mut H) -> bool where H: EventHandler {
    while let Ok((key, action)) = self.kbd.try_recv() {
      if !handler.on_key(key, action) {
        return false;
      }
    }

    while let Ok((button, action)) = self.mouse.try_recv() {
      if !handler.on_mouse_button(button, action) {
        return false;
      }
    }

    while let Ok(xy) = self.cursor.try_recv() {
      if !handler.on_cursor_move(xy) {
        return false;
      }
    }

    while let Ok(xy) = self.scroll.try_recv() {
      if !handler.on_scroll(xy) {
        return false;
      }
    }

    true
  }

  /// Step function.
  ///
  /// This function provides two features:
  ///
  /// - it runs a *drawer* function, responsible of rendering a single frame, by passing it the
  ///   current time
  /// - it performs process idleing if you have requested a certain *framerate* – frame per second.
  ///
  /// The second feature is very neat because it lets you handle the scheduler off your application
  /// and then contribute to better CPU usage.
  ///
  /// > Note: if you pass `None`, no idleing will take place. However, you might be blocked by the
  /// *VSync* if enabled in your driver.
  pub fn step<FPS, R>(&mut self, fps: FPS, mut draw_frame: R) -> bool where FPS: Into<Option<u32>>, R: FnMut(f64) {
    if self.window.should_close() {
      return false;
    }

    let t = self.time();

    draw_frame(t);
    self.window.swap_buffers();

    // wait for next frame according to the wished FPS
    if let Some(fps) = fps.into() {
      let fps = fps as f64;
      let max_time = 1. / fps;
      let elapsed_time = self.time() - t;

      if elapsed_time < max_time {
        let sleep_time = max_time - elapsed_time;
        thread::sleep(Duration::from_millis((sleep_time * 1e3) as u64));
      }
    }

    true
  }
}

/// Freefly handler.
///
/// This handler is very neat as it provides freefly interaction.
pub struct FreeflyHandler {
  camera: Rc<RefCell<Camera<Freefly>>>,
  left_down: bool,
  right_down: bool,
  last_cursor: [f64; 2]
}

impl FreeflyHandler {
  pub fn new(camera: Rc<RefCell<Camera<Freefly>>>) -> Self {
    FreeflyHandler {
      camera: camera,
      left_down: false,
      right_down: false,
      last_cursor: [0., 0.]
    }
  }

  fn move_camera_on_event(&mut self, key: Key) {
    let camera = &mut self.camera.borrow_mut();

    match key {
      Key::W => camera.mv(Translation::new(0., 0., 1.)),
      Key::S => camera.mv(Translation::new(0., 0., -1.)),
      Key::A => camera.mv(Translation::new(1., 0., 0.)),
      Key::D => camera.mv(Translation::new(-1., 0., 0.)),
      Key::Q => camera.mv(Translation::new(0., -1., 0.)),
      Key::E => camera.mv(Translation::new(0., 1., 0.)),
      _ => ()
    }
  }

  fn orient_camera_on_event(&mut self, cursor: [f64; 2]) {
    let camera = &mut self.camera.borrow_mut();

    if self.left_down {
      let (dx, dy) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(dy as f32, dx as f32, 0.));
    } else if self.right_down {
      let (dx, _) = (cursor[0] - self.last_cursor[0], cursor[1] - self.last_cursor[1]);
      camera.look_around(Translation::new(0., 0., dx as f32));
    }

    self.last_cursor = cursor;
  }
}

impl EventHandler for FreeflyHandler {
  fn on_key(&mut self, key: Key, action: Action) -> bool {
    match action {
      Action::Press | Action::Repeat => self.move_camera_on_event(key),
      Action::Release => if key == Key::Escape { return false }
    }

    true
  }

  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> bool {
    match (button, action) {
      (MouseButton::Button1, Action::Press) => {
        self.left_down = true;
      },
      (MouseButton::Button1, Action::Release) => {
        self.left_down = false;
      },
      (MouseButton::Button2, Action::Press) => {
        self.right_down = true;
      },
      (MouseButton::Button2, Action::Release) => {
        self.right_down = false;
      },
      _ => ()
    }

    true
  }

  fn on_cursor_move(&mut self, dir: [f64; 2]) -> bool {
    self.orient_camera_on_event(dir);
    true
  }
}
<|endoftext|>


<commit_before>#![crate_name="cargo"]
#![crate_type="rlib"]

#![feature(macro_rules, phase)]
#![feature(default_type_params)]
#![deny(warnings)]

extern crate collections;
extern crate debug;
extern crate regex;
extern crate semver;
extern crate serialize;
extern crate term;
extern crate time;
extern crate url;
#[phase(plugin)] extern crate regex_macros;
#[phase(plugin, link)] extern crate log;

extern crate docopt;
extern crate toml;
#[cfg(test)] extern crate hamcrest;

use std::os;
use std::io::stdio::{stdout_raw, stderr_raw};
use std::io::{stdout, stderr};
use std::io;
use serialize::{Decoder, Encoder, Decodable, Encodable, json};
use docopt::FlagParser;

use core::{Shell, MultiShell, ShellConfig};
use term::color::{BLACK};

pub use util::{CargoError, CliError, CliResult, human};

macro_rules! some(
    ($e:expr) => (
        match $e {
            Some(e) => e,
            None => return None
        }
    )
)

// Added so that the try! macro below can refer to cargo::util, while
// other external importers of this macro can use it as well.
//
// "Hygiene strikes again" - @acrichton
mod cargo {
    pub use super::util;
}

#[macro_export]
macro_rules! try (
    ($expr:expr) => ({
        use cargo::util::FromError;
        match $expr.map_err(FromError::from_error) {
            Ok(val) => val,
            Err(err) => return Err(err)
        }
    })
)

macro_rules! raw_try (
    ($expr:expr) => ({
        match $expr {
            Ok(val) => val,
            Err(err) => return Err(err)
        }
    })
)

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

trait RepresentsJSON : Decodable<json::Decoder, json::DecoderError> {}
impl<T: Decodable<json::Decoder, json::DecoderError>> RepresentsJSON for T {}

pub fn execute_main<'a,
                    T: FlagParser,
                    U: RepresentsJSON,
                    V: Encodable<json::Encoder<'a>, io::IoError>>(
                        exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
                        options_first: bool) {
    process::<V>(|rest, shell| call_main(exec, shell, rest, options_first));
}

pub fn call_main<'a,
        T: FlagParser,
        U: RepresentsJSON,
        V: Encodable<json::Encoder<'a>, io::IoError>>(
            exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
            shell: &mut MultiShell,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>> {
    let flags = try!(flags_from_args::<T>(args, options_first));
    let json = try!(json_from_stdin::<U>());

    exec(flags, json, shell)
}

pub fn execute_main_without_stdin<'a,
                                  T: FlagParser,
                                  V: Encodable<json::Encoder<'a>, io::IoError>>(
                                      exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
                                      options_first: bool) {
    process::<V>(|rest, shell| call_main_without_stdin(exec, shell, rest,
                                                       options_first));
}

pub fn call_main_without_stdin<'a,
                               T: FlagParser,
                               V: Encodable<json::Encoder<'a>, io::IoError>>(
            exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
            shell: &mut MultiShell,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>> {
    let flags = try!(flags_from_args::<T>(args, options_first));
    exec(flags, shell)
}

fn process<'a, V: Encodable<json::Encoder<'a>, io::IoError>>(
               callback: |&[String], &mut MultiShell| -> CliResult<Option<V>>) {
    let mut shell = shell(true);
    let mut args = os::args();
    args.remove(0);
    process_executed(callback(args.as_slice(), &mut shell), &mut shell)
}

pub fn process_executed<'a,
                        T: Encodable<json::Encoder<'a>, io::IoError>>(
                            result: CliResult<Option<T>>,
                            shell: &mut MultiShell) {
    match result {
        Err(e) => handle_error(e, shell),
        Ok(encodable) => {
            encodable.map(|encodable| {
                let encoded = json::encode(&encodable);
                println!("{}", encoded);
            });
        }
    }
}

pub fn shell(verbose: bool) -> MultiShell {
    let tty = stderr_raw().isatty();
    let stderr = box stderr() as Box<Writer>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let err = Shell::create(stderr, config);

    let tty = stdout_raw().isatty();
    let stdout = box stdout() as Box<Writer>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let out = Shell::create(stdout, config);

    MultiShell::new(out, err, verbose)
}

pub fn handle_error(err: CliError, shell: &mut MultiShell) {
    log!(4, "handle_error; err={}", err);

    let CliError { error, exit_code, unknown } = err;

    if unknown {
        let _ = shell.error("An unknown error occurred");
    } else if error.to_string().len() > 0 {
        let _ = shell.error(error.to_string());
    }

    if error.cause().is_some() || unknown {
        let _ = shell.concise(|shell| {
            shell.err().say("\nTo learn more, run the command again with --verbose.", BLACK)
        });
    }

    let _ = shell.verbose(|shell| {
        if unknown {
            let _ = shell.error(error.to_string());
        }
        error.detail().map(|detail| {
            let _ = shell.err().say(format!("{}", detail), BLACK);
        });
        error.cause().map(|err| {
            let _ = handle_cause(err, shell);
        });
        Ok(())
      });

    std::os::set_exit_status(exit_code as int);
}

fn handle_cause(err: &CargoError, shell: &mut MultiShell) {
    let _ = shell.err().say("\nCaused by:", BLACK);
    let _ = shell.err().say(format!("  {}", err.description()), BLACK);

    err.cause().map(|e| handle_cause(e, shell));
}

pub fn version() -> String {
    format!("cargo {}", env!("CFG_VERSION"))
}

fn flags_from_args<T: FlagParser>(args: &[String],
                                  options_first: bool) -> CliResult<T> {
    let args = args.iter().map(|a| a.as_slice()).collect::<Vec<&str>>();
    let config = docopt::Config {
        options_first: options_first,
        help: true,
        version: Some(version()),
    };
    FlagParser::parse_args(config, args.as_slice()).map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::from_error(e, code)
    })
}

fn json_from_stdin<T: RepresentsJSON>() -> CliResult<T> {
    let mut reader = io::stdin();
    let input = try!(reader.read_to_string().map_err(|_| {
        CliError::new("Standard in did not exist or was not UTF-8", 1)
    }));

    let json = try!(json::from_str(input.as_slice()).map_err(|_| {
        CliError::new("Could not parse standard in as JSON", 1)
    }));
    let mut decoder = json::Decoder::new(json);

    Decodable::decode(&mut decoder).map_err(|_| {
        CliError::new("Could not process standard in as input", 1)
    })
}
<commit_msg>auto merge of #328 : alexcrichton/cargo/cargo-building-cargo, r=wycats<commit_after>#![crate_name="cargo"]
#![crate_type="rlib"]

#![feature(macro_rules, phase)]
#![feature(default_type_params)]
#![deny(warnings)]

extern crate collections;
extern crate debug;
extern crate regex;
extern crate semver;
extern crate serialize;
extern crate term;
extern crate time;
extern crate url;
#[phase(plugin)] extern crate regex_macros;
#[phase(plugin, link)] extern crate log;

extern crate docopt;
extern crate toml;
#[cfg(test)] extern crate hamcrest;

use std::os;
use std::io::stdio::{stdout_raw, stderr_raw};
use std::io::{stdout, stderr};
use std::io;
use serialize::{Decoder, Encoder, Decodable, Encodable, json};
use docopt::FlagParser;

use core::{Shell, MultiShell, ShellConfig};
use term::color::{BLACK};

pub use util::{CargoError, CliError, CliResult, human};

macro_rules! some(
    ($e:expr) => (
        match $e {
            Some(e) => e,
            None => return None
        }
    )
)

// Added so that the try! macro below can refer to cargo::util, while
// other external importers of this macro can use it as well.
//
// "Hygiene strikes again" - @acrichton
mod cargo {
    pub use super::util;
}

#[macro_export]
macro_rules! try (
    ($expr:expr) => ({
        use cargo::util::FromError;
        match $expr.map_err(FromError::from_error) {
            Ok(val) => val,
            Err(err) => return Err(err)
        }
    })
)

macro_rules! raw_try (
    ($expr:expr) => ({
        match $expr {
            Ok(val) => val,
            Err(err) => return Err(err)
        }
    })
)

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

trait RepresentsJSON : Decodable<json::Decoder, json::DecoderError> {}
impl<T: Decodable<json::Decoder, json::DecoderError>> RepresentsJSON for T {}

pub fn execute_main<'a,
                    T: FlagParser,
                    U: RepresentsJSON,
                    V: Encodable<json::Encoder<'a>, io::IoError>>(
                        exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
                        options_first: bool) {
    process::<V>(|rest, shell| call_main(exec, shell, rest, options_first));
}

pub fn call_main<'a,
        T: FlagParser,
        U: RepresentsJSON,
        V: Encodable<json::Encoder<'a>, io::IoError>>(
            exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
            shell: &mut MultiShell,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>> {
    let flags = try!(flags_from_args::<T>(args, options_first));
    let json = try!(json_from_stdin::<U>());

    exec(flags, json, shell)
}

pub fn execute_main_without_stdin<'a,
                                  T: FlagParser,
                                  V: Encodable<json::Encoder<'a>, io::IoError>>(
                                      exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
                                      options_first: bool) {
    process::<V>(|rest, shell| call_main_without_stdin(exec, shell, rest,
                                                       options_first));
}

pub fn call_main_without_stdin<'a,
                               T: FlagParser,
                               V: Encodable<json::Encoder<'a>, io::IoError>>(
            exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
            shell: &mut MultiShell,
            args: &[String],
            options_first: bool) -> CliResult<Option<V>> {
    let flags = try!(flags_from_args::<T>(args, options_first));
    exec(flags, shell)
}

fn process<'a, V: Encodable<json::Encoder<'a>, io::IoError>>(
               callback: |&[String], &mut MultiShell| -> CliResult<Option<V>>) {
    let mut shell = shell(true);
    let mut args = os::args();
    args.remove(0);
    process_executed(callback(args.as_slice(), &mut shell), &mut shell)
}

pub fn process_executed<'a,
                        T: Encodable<json::Encoder<'a>, io::IoError>>(
                            result: CliResult<Option<T>>,
                            shell: &mut MultiShell) {
    match result {
        Err(e) => handle_error(e, shell),
        Ok(encodable) => {
            encodable.map(|encodable| {
                let encoded = json::encode(&encodable);
                println!("{}", encoded);
            });
        }
    }
}

pub fn shell(verbose: bool) -> MultiShell {
    let tty = stderr_raw().isatty();
    let stderr = box stderr() as Box<Writer>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let err = Shell::create(stderr, config);

    let tty = stdout_raw().isatty();
    let stdout = box stdout() as Box<Writer>;

    let config = ShellConfig { color: true, verbose: verbose, tty: tty };
    let out = Shell::create(stdout, config);

    MultiShell::new(out, err, verbose)
}

pub fn handle_error(err: CliError, shell: &mut MultiShell) {
    log!(4, "handle_error; err={}", err);

    let CliError { error, exit_code, unknown } = err;

    if unknown {
        let _ = shell.error("An unknown error occurred");
    } else if error.to_string().len() > 0 {
        let _ = shell.error(error.to_string());
    }

    if error.cause().is_some() || unknown {
        let _ = shell.concise(|shell| {
            shell.err().say("\nTo learn more, run the command again with --verbose.", BLACK)
        });
    }

    let _ = shell.verbose(|shell| {
        if unknown {
            let _ = shell.error(error.to_string());
        }
        error.detail().map(|detail| {
            let _ = shell.err().say(format!("{}", detail), BLACK);
        });
        error.cause().map(|err| {
            let _ = handle_cause(err, shell);
        });
        Ok(())
      });

    std::os::set_exit_status(exit_code as int);
}

fn handle_cause(err: &CargoError, shell: &mut MultiShell) {
    let _ = shell.err().say("\nCaused by:", BLACK);
    let _ = shell.err().say(format!("  {}", err.description()), BLACK);

    err.cause().map(|e| handle_cause(e, shell));
}

pub fn version() -> String {
    format!("cargo {}", match option_env!("CFG_VERSION") {
        Some(s) => s.to_string(),
        None => format!("{}.{}.{}{}",
                        env!("CARGO_PKG_VERSION_MAJOR"),
                        env!("CARGO_PKG_VERSION_MINOR"),
                        env!("CARGO_PKG_VERSION_PATCH"),
                        option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
    })
}

fn flags_from_args<T: FlagParser>(args: &[String],
                                  options_first: bool) -> CliResult<T> {
    let args = args.iter().map(|a| a.as_slice()).collect::<Vec<&str>>();
    let config = docopt::Config {
        options_first: options_first,
        help: true,
        version: Some(version()),
    };
    FlagParser::parse_args(config, args.as_slice()).map_err(|e| {
        let code = if e.fatal() {1} else {0};
        CliError::from_error(e, code)
    })
}

fn json_from_stdin<T: RepresentsJSON>() -> CliResult<T> {
    let mut reader = io::stdin();
    let input = try!(reader.read_to_string().map_err(|_| {
        CliError::new("Standard in did not exist or was not UTF-8", 1)
    }));

    let json = try!(json::from_str(input.as_slice()).map_err(|_| {
        CliError::new("Could not parse standard in as JSON", 1)
    }));
    let mut decoder = json::Decoder::new(json);

    Decodable::decode(&mut decoder).map_err(|_| {
        CliError::new("Could not process standard in as input", 1)
    })
}
<|endoftext|>


<commit_before>//! A text character

use types::FontSize;
use ImageSize;

/// Holds rendered character data.
#[derive(Clone)]
pub struct Character<T: ImageSize> {
    /// The offset of character.
    pub offset: [f64; 2],
    /// The size of character, including space.
    pub size: [f64; 2],
    /// The texture of the character.
    pub texture: T,
}

impl<T: ImageSize> Character<T> {
    /// The left offset.
    pub fn left(&self) -> f64 {
        self.offset[0]
    }

    /// The top offset.
    pub fn top(&self) -> f64 {
        self.offset[1]
    }

    /// Gets width of character, including space to the next one.
    pub fn width(&self) -> f64 {
        self.size[0]
    }

    /// Sets height of character, including space to the next one.
    pub fn height(&self) -> f64 {
        self.size[1]
    }
}

/// Stores characters in a buffer and loads them by demand.
pub trait CharacterCache {
    /// The textyre type associated with the character cache.
    type Texture: ImageSize;

    /// Get reference to character.
    fn character(
        &mut self,
        font_size: FontSize,
        ch: char
    ) -> &Character<<Self as CharacterCache>::Texture>;
}
<commit_msg>Added method to CharacterCache for determining the width of some given text.<commit_after>//! A text character

use types::FontSize;
use ImageSize;

/// Holds rendered character data.
#[derive(Clone)]
pub struct Character<T: ImageSize> {
    /// The offset of character.
    pub offset: [f64; 2],
    /// The size of character, including space.
    pub size: [f64; 2],
    /// The texture of the character.
    pub texture: T,
}

impl<T: ImageSize> Character<T> {
    /// The left offset.
    pub fn left(&self) -> f64 {
        self.offset[0]
    }

    /// The top offset.
    pub fn top(&self) -> f64 {
        self.offset[1]
    }

    /// Gets width of character, including space to the next one.
    pub fn width(&self) -> f64 {
        self.size[0]
    }

    /// Sets height of character, including space to the next one.
    pub fn height(&self) -> f64 {
        self.size[1]
    }
}

/// Stores characters in a buffer and loads them by demand.
pub trait CharacterCache {
    /// The textyre type associated with the character cache.
    type Texture: ImageSize;

    /// Get reference to character.
    fn character(
        &mut self,
        font_size: FontSize,
        ch: char
    ) -> &Character<<Self as CharacterCache>::Texture>;

    /// Return the width for some given text.
    fn width(&mut self, size: FontSize, text: &str) -> ::math::Scalar {
        text.chars().fold(0, |a, ch| {
            let character = self.character(size, ch);
            a + character.width() as u32
        }) as f64
    }
}
<|endoftext|>


<commit_before>use csv;
use regex::Regex;
use std::result::Result;
use std::str;
use std::process;
use curl::http;
use rustc_serialize::json;

fn get_page(url: String, token: &str) -> http::Response {
    let auth_header = format!("token {}", token);
    let res = http::handle()
                   .get(url)
                   .header("Authorization", &auth_header)
                   .header("User-Agent", "Github-Issues-CLI")
                   .header("Accept", "application/vnd.github.v3+json")
                   .exec()
                   .unwrap_or_else(|e| process::exit(1));

    res
}

fn next_url(link: String) -> Option<String> {
    let re = Regex::new(r"<([^;]+)>;\s*rel=.next.").unwrap();
    match re.captures(&link) {
        None => None,
        Some(cs) => cs.at(1).as_ref().map(|x| x.to_string())
    }
}

fn to_issues(raw: &[u8]) -> Result<Vec<Issue>, json::DecoderError> {
    match str::from_utf8(raw) {
        Ok(b) => json::decode(b),
        Err(..) => {
            println!("Unable to parse the response from Github");
            process::exit(1)
        }
    }
}

pub fn run(owner: &str,
           repo: &str,
           oauth_token: String,
           labels: Vec<String>,
           output_file: String) {

    let page = 1;
    let url = format!("https://api.github.com/repos/{}/{}/issues?state=all&page={}&labels={}",
                      owner, repo, page, labels.join(","));
    println!("Fetching {:?}", url);
    let res = get_page(url, &oauth_token);
    let mut issues = to_issues(res.get_body()).unwrap();

    match res.get_headers().get("link") {
        Some(links) => {
            let mut nurl = next_url(links.first().unwrap().clone());

            while let Some(nu) = nurl {
                println!("Fetching {:?}", nu);
                let r = get_page(nu.to_string(), &oauth_token);
                issues.extend(to_issues(r.get_body()).unwrap());

                let link = r.get_headers().get("link").unwrap()
                                          .first().unwrap()
                                          .clone();
                nurl = next_url(link);
            }
        }
        _ => {}
    }

    // let mut wtr = csv::Writer::from_memory();
    let mut wtr = csv::Writer::from_file(output_file).unwrap();
    let headers = ("number",
                   "title",
                   "state",
                   "created_at",
                   "closed_at",
                   "assignee",
                   "user",
                   "labels",
                   "body");
    wtr.encode(headers);

    println!("Total issues collected: {:?}", issues.len());

    for issue in issues {
        let labels = issue.labels.iter()
                                 .map(|x| x.name.clone())
                                 .collect::<Vec<String>>()
                                 .join(",");
        let user = issue.user;
        let assignee = issue.assignee;

        let row = (issue.number,
                   issue.title,
                   issue.state,
                   issue.created_at,
                   issue.closed_at,
                   assignee,
                   user,
                   labels,
                   issue.body);

        // println!("{:?}", row);
        // let result = wtr.encode(row);
        // println!("{:?}", result.is_ok());
        wtr.encode(row);
    }

    // println!("{:?}", wtr.as_string());
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Issue {
    assignee: Option<User>,
    body: Option<String>,
    created_at: Option<String>,
    closed_at: Option<String>,
    labels: Vec<Label>,
    number: u32,
    state: Option<String>,
    title: Option<String>,
    user: Option<User>,
}

type Issues = Vec<Issue>;

type Labels = Vec<Label>;

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Label {
    color: String,
    name: String,
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct User {
    login: String,
}
<commit_msg>Refine types<commit_after>use csv;
use regex::Regex;
use std::result::Result;
use std::str;
use std::process;
use curl::http;
use rustc_serialize::json;

fn get_page(url: String, token: &str) -> http::Response {
    let auth_header = format!("token {}", token);
    let res = http::handle()
                   .get(url)
                   .header("Authorization", &auth_header)
                   .header("User-Agent", "Github-Issues-CLI")
                   .header("Accept", "application/vnd.github.v3+json")
                   .exec()
                   .unwrap_or_else(|e| process::exit(1));

    res
}

fn next_url(link: String) -> Option<String> {
    let re = Regex::new(r"<([^;]+)>;\s*rel=.next.").unwrap();
    match re.captures(&link) {
        None => None,
        Some(cs) => cs.at(1).as_ref().map(|x| x.to_string())
    }
}

fn to_issues(raw: &[u8]) -> Result<Issues, json::DecoderError> {
    match str::from_utf8(raw) {
        Ok(b) => json::decode(b),
        Err(..) => {
            println!("Unable to parse the response from Github");
            process::exit(1)
        }
    }
}

pub fn run(owner: &str,
           repo: &str,
           oauth_token: String,
           labels: Vec<String>,
           output_file: String) {

    let page = 1;
    let url = format!("https://api.github.com/repos/{}/{}/issues?state=all&page={}&labels={}",
                      owner, repo, page, labels.join(","));

    println!("Fetching {:?}", url);
    let res = get_page(url, &oauth_token);
    let mut issues = to_issues(res.get_body()).unwrap();

    match res.get_headers().get("link") {
        Some(links) => {
            let mut nurl = next_url(links.first().unwrap().clone());

            while let Some(nu) = nurl {
                println!("Fetching {:?}", nu);
                let r = get_page(nu.to_string(), &oauth_token);
                issues.extend(to_issues(r.get_body()).unwrap());

                let link = r.get_headers().get("link").unwrap()
                                          .first().unwrap()
                                          .clone();
                nurl = next_url(link);
            }
        }
        _ => {}
    }

    // let mut wtr = csv::Writer::from_memory();
    let mut wtr = csv::Writer::from_file(output_file).unwrap();
    let headers = ("number",
                   "title",
                   "state",
                   "created_at",
                   "closed_at",
                   "assignee",
                   "user",
                   "labels",
                   "body");
    wtr.encode(headers);

    println!("Total issues collected: {:?}", issues.len());

    for issue in issues {
        let labels = issue.labels.iter()
                                 .map(|x| x.name.clone())
                                 .collect::<Vec<String>>()
                                 .join(",");
        let user = issue.user;
        let assignee = issue.assignee;

        let row = (issue.number,
                   issue.title,
                   issue.state,
                   issue.created_at,
                   issue.closed_at,
                   assignee,
                   user,
                   labels,
                   issue.body);

        // println!("{:?}", row);
        // let result = wtr.encode(row);
        // println!("{:?}", result.is_ok());
        wtr.encode(row);
    }

    // println!("{:?}", wtr.as_string());
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Issue {
    assignee: Option<User>,
    body: Option<String>,
    created_at: Option<String>,
    closed_at: Option<String>,
    labels: Labels,
    number: u32,
    state: Option<String>,
    title: Option<String>,
    user: Option<User>,
}

type Issues = Vec<Issue>;

type Labels = Vec<Label>;

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Label {
    color: String,
    name: String,
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
struct User {
    login: String,
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use csv;
use curl::http;
use regex::Regex;
use rustc_serialize::json;
use std::collections::HashMap;
use std::fs::File;
use std::process;
use std::result::Result;
use std::str;

use say;
use format::{OutputFormat};
use github::entities::{Issue, Issues, GithubError};

fn ratelimit(headers: &HashMap<String, Vec<String>>) -> String {
    headers.get("x-ratelimit-remaining").unwrap()
           .first().unwrap().to_string()
}
#[test]
fn valid_ratelimit() {
    let mut headers: HashMap<String, Vec<String>> = HashMap::new();
    headers.insert("x-ratelimit-remaining".to_owned(), vec!["1".to_owned()]);

    assert_eq!(ratelimit(&headers), "1");
}

fn get_page(url: String, token: &str) -> http::Response {
    println!("{} {} {}", say::info(), "Fetching", url);

    let auth_header = format!("token {}", token);
    let res = http::handle()
                   .get(url)
                   .header("Authorization", &auth_header)
                   .header("User-Agent", "Github-Issues-CLI")
                   .header("Accept", "application/vnd.github.v3+json")
                   .exec()
                   .unwrap_or_else(|e| process::exit(1));

    if res.get_code() != 200 {
        match str::from_utf8(res.get_body()) {
            Ok(b) => {
                println!("{} {:?}", say::error(), json::decode::<GithubError>(b).ok());
                process::exit(1)
            }
            Err(..) => {
                println!("{} {}", say::error(), "Unable to parse the response from Github");
                process::exit(1)
            }
        }
    }

    res
}

fn next_url(link: String) -> Option<String> {
    let re = Regex::new(r"<([^;]+)>;\s*rel=.next.").unwrap();
    match re.captures(&link) {
        None => None,
        Some(cs) => cs.at(1).as_ref().map(|x| x.to_string())
    }
}

fn as_issues(raw: &[u8]) -> Result<Issues, json::DecoderError> {
    match str::from_utf8(raw) {
        Ok(b) => json::decode(b),
        Err(..) => {
            println!("{} {}", say::error(), "Unable to parse the response from Github");
            process::exit(1)
        }
    }
}

fn parse_repopath(path: String) -> (String, String) {
    let list: Vec<&str> = path.split("/").collect();

    (list[0].to_string(), list[1].to_string())
}

pub fn run(repopath: String,
           oauth_token: String,
           labels: Vec<String>,
           state: String,
           format: OutputFormat,
           output_file: String) {

    // let (owner, repo) = parse_repopath(repopath);
    let labels_pair = if labels.is_empty() { "".to_owned() }
                      else { format!("&labels={}", labels.join(",")) };
    let url = format!("https://api.github.com/repos/{}/issues?filter=all&state={}{}",
                      repopath, state, labels_pair);

    let res = get_page(url, &oauth_token);
    let mut issues = as_issues(res.get_body()).unwrap();

    // A Link header is not present if the requested collection has less than
    // _pagesize_.
    match res.get_headers().get("link") {
        Some(links) => {
            let mut nurl = next_url(links.first().unwrap().clone());

            while let Some(nu) = nurl {
                let r = get_page(nu.to_string(), &oauth_token);
                issues.extend(as_issues(r.get_body()).unwrap());

                let link = r.get_headers().get("link").unwrap()
                                          .first().unwrap()
                                          .clone();
                nurl = next_url(link);
                if nurl.is_none() {
                    println!("{} {} {}", say::warn(), ratelimit(r.get_headers()), "Remaining requests");
                }
            }
        }
        _ => {
            println!("{} {} {}", say::warn(), ratelimit(res.get_headers()), "Remaining requests");
        }
    }

    println!("{} {}", say::highlight("Total issues collected:"), issues.len());

    match format {
        OutputFormat::CSV => write_csv(issues, output_file),
        OutputFormat::JSON => write_json(issues, output_file),
    }
}

fn write_json(issues: Issues, output_file: String) {
    let mut f = File::create(output_file).unwrap();
    let string: String = json::encode(&issues).unwrap();
    f.write_all(string.as_bytes());
}

fn write_csv(issues: Issues, output_file: String) {
    let mut wtr = csv::Writer::from_file(output_file).unwrap();

    let headers = ("number",
                   "title",
                   "state",
                   "created_at",
                   "closed_at",
                   "assignee",
                   "user",
                   "labels",
                   "body");
    wtr.encode(headers);

    for issue in issues {
        let labels = issue.labels.iter()
                                 .map(|x| x.name.clone())
                                 .collect::<Vec<String>>()
                                 .join(",");
        let user = issue.user;
        let assignee = issue.assignee;

        let row = (issue.number,
                   issue.title,
                   issue.state,
                   issue.created_at,
                   issue.closed_at,
                   assignee,
                   user,
                   labels,
                   issue.body);

        wtr.encode(row);
    }
}
<commit_msg>Cast ratelimit as integer<commit_after>use std::io::prelude::*;
use csv;
use curl::http;
use regex::Regex;
use rustc_serialize::json;
use std::collections::HashMap;
use std::fs::File;
use std::process;
use std::result::Result;
use std::str;

use say;
use format::{OutputFormat};
use github::entities::{Issue, Issues, GithubError};

fn ratelimit(headers: &HashMap<String, Vec<String>>) -> u32 {
    let rate = headers.get("x-ratelimit-remaining").unwrap()
                      .first().unwrap();

    rate.parse().unwrap()
}
#[test]
fn valid_ratelimit() {
    let mut headers: HashMap<String, Vec<String>> = HashMap::new();
    headers.insert("x-ratelimit-remaining".to_owned(), vec!["1".to_owned()]);

    assert_eq!(ratelimit(&headers), 1);
}

fn get_page(url: String, token: &str) -> http::Response {
    println!("{} {} {}", say::info(), "Fetching", url);

    let auth_header = format!("token {}", token);
    let res = http::handle()
                   .get(url)
                   .header("Authorization", &auth_header)
                   .header("User-Agent", "Github-Issues-CLI")
                   .header("Accept", "application/vnd.github.v3+json")
                   .exec()
                   .unwrap_or_else(|e| process::exit(1));

    if res.get_code() != 200 {
        match str::from_utf8(res.get_body()) {
            Ok(b) => {
                println!("{} {:?}", say::error(), json::decode::<GithubError>(b).ok());
                process::exit(1)
            }
            Err(..) => {
                println!("{} {}", say::error(), "Unable to parse the response from Github");
                process::exit(1)
            }
        }
    }

    res
}

fn next_url(link: String) -> Option<String> {
    let re = Regex::new(r"<([^;]+)>;\s*rel=.next.").unwrap();
    match re.captures(&link) {
        None => None,
        Some(cs) => cs.at(1).as_ref().map(|x| x.to_string())
    }
}

fn as_issues(raw: &[u8]) -> Result<Issues, json::DecoderError> {
    match str::from_utf8(raw) {
        Ok(b) => json::decode(b),
        Err(..) => {
            println!("{} {}", say::error(), "Unable to parse the response from Github");
            process::exit(1)
        }
    }
}

fn parse_repopath(path: String) -> (String, String) {
    let list: Vec<&str> = path.split("/").collect();

    (list[0].to_string(), list[1].to_string())
}

pub fn run(repopath: String,
           oauth_token: String,
           labels: Vec<String>,
           state: String,
           format: OutputFormat,
           output_file: String) {

    // let (owner, repo) = parse_repopath(repopath);
    let labels_pair = if labels.is_empty() { "".to_owned() }
                      else { format!("&labels={}", labels.join(",")) };
    let url = format!("https://api.github.com/repos/{}/issues?filter=all&state={}{}",
                      repopath, state, labels_pair);

    let res = get_page(url, &oauth_token);
    let mut issues = as_issues(res.get_body()).unwrap();

    // A Link header is not present if the requested collection has less than
    // _pagesize_.
    match res.get_headers().get("link") {
        Some(links) => {
            let mut nurl = next_url(links.first().unwrap().clone());

            while let Some(nu) = nurl {
                let r = get_page(nu.to_string(), &oauth_token);
                issues.extend(as_issues(r.get_body()).unwrap());

                let link = r.get_headers().get("link").unwrap()
                                          .first().unwrap()
                                          .clone();
                nurl = next_url(link);
                if nurl.is_none() {
                    println!("{} {} {}", say::warn(), ratelimit(r.get_headers()), "Remaining requests");
                }
            }
        }
        _ => {
            println!("{} {} {}", say::warn(), ratelimit(res.get_headers()), "Remaining requests");
        }
    }

    println!("{} {}", say::highlight("Total issues collected:"), issues.len());

    match format {
        OutputFormat::CSV => write_csv(issues, output_file),
        OutputFormat::JSON => write_json(issues, output_file),
    }
}

fn write_json(issues: Issues, output_file: String) {
    let mut f = File::create(output_file).unwrap();
    let string: String = json::encode(&issues).unwrap();
    f.write_all(string.as_bytes());
}

fn write_csv(issues: Issues, output_file: String) {
    let mut wtr = csv::Writer::from_file(output_file).unwrap();

    let headers = ("number",
                   "title",
                   "state",
                   "created_at",
                   "closed_at",
                   "assignee",
                   "user",
                   "labels",
                   "body");
    wtr.encode(headers);

    for issue in issues {
        let labels = issue.labels.iter()
                                 .map(|x| x.name.clone())
                                 .collect::<Vec<String>>()
                                 .join(",");
        let user = issue.user;
        let assignee = issue.assignee;

        let row = (issue.number,
                   issue.title,
                   issue.state,
                   issue.created_at,
                   issue.closed_at,
                   assignee,
                   user,
                   labels,
                   issue.body);

        wtr.encode(row);
    }
}
<|endoftext|>


<commit_before>use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::cmp::Ordering;
use std::io::*;
use std::str;

#[derive(PartialEq, PartialOrd, Clone, Debug)]
pub struct Point {
    pub t: i32,
    pub val: f32,
}
impl Eq for Point {}
impl Ord for Point {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[derive(PartialEq, PartialOrd, Eq, Ord, Clone, Debug)]
pub struct BinaryTimeSeries {
    pub name: String,
    pub data: Vec<Point>,
}

#[derive(Clone, PartialEq)]
pub struct CorrelatedTimeSeries<'a> {
    pub series: &'a BinaryTimeSeries,
    pub correlation: f32,
}
impl<'a> PartialOrd for CorrelatedTimeSeries<'a> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        other.correlation.partial_cmp(&self.correlation)
    }
}

pub fn read_btsf_file<T: Read + Seek>(
    f: &mut T,
    series: &mut Vec<BinaryTimeSeries>,
) -> Result<usize> {
    try!(f.seek(SeekFrom::Start(0)));
    let _ = try!(f.read_u32::<LittleEndian>());
    let file_header_len = try!(f.read_u32::<LittleEndian>());
    let rec_header_len = try!(f.read_u32::<LittleEndian>());
    let num_records = try!(f.read_u32::<LittleEndian>());

    try!(f.seek(SeekFrom::Start(file_header_len as u64)));

    // println!("Version Number: {}", version);
    // println!("File Header Len: {}", file_header_len);
    // println!("Rec Header Len: {}", rec_header_len);
    // println!("Num Records: {}", num_records);

    series.reserve(num_records as usize);
    for _ in 0..num_records {
        let n = try!(f.read_u32::<LittleEndian>());
        let name_length = try!(f.read_u32::<LittleEndian>());
        try!(f.seek(SeekFrom::Current((rec_header_len - 8) as i64))); // Skip padding bytes;

        let mut buffer = [0; 1024];
        try!(f.take(name_length as u64).read(&mut buffer));

        let name = match str::from_utf8(&buffer[0..(name_length as usize)]) {
            Ok(s) => s,
            Err(_) => return Err(Error::new(ErrorKind::InvalidInput, "Invalid input UTF-8")),
        };

        let mut data = Vec::<Point>::new();

        for _ in 0..n {
            let t = try!(f.read_i32::<LittleEndian>());
            let d = try!(f.read_f32::<LittleEndian>());
            data.push(Point { t: t, val: d });
        }
        series.push(BinaryTimeSeries {
            name: String::from(name),
            data: data,
        })
    }

    return Ok(num_records as usize);
}

pub fn write_btsf_file<T: Write>(data: &[&BinaryTimeSeries], output: &mut T) -> Result<()> {
    // Version Header, File Header Len, Rec Header Len
    try!(output.write_u32::<LittleEndian>(2));
    try!(output.write_u32::<LittleEndian>(4 * 4));
    try!(output.write_u32::<LittleEndian>(4 * 2));

    try!(output.write_u32::<LittleEndian>(data.len() as u32));

    for record in data {
        try!(output.write_u32::<LittleEndian>(record.data.len() as u32));
        try!(output.write_u32::<LittleEndian>(record.name.len() as u32));
        try!(output.write(&record.name.as_bytes()));
        for i in 0..record.data.len() {
            try!(output.write_i32::<LittleEndian>(record.data[i].t));
            try!(output.write_f32::<LittleEndian>(record.data[i].val));
        }
    }
    Ok(())
}

pub fn write_correlated_btsf_file<T: Write>(
    data: &[CorrelatedTimeSeries],
    output: &mut T,
) -> Result<()> {
    // Version Header, File Header Len, Rec Header Len
    try!(output.write_u32::<LittleEndian>(2));
    try!(output.write_u32::<LittleEndian>(4 * 4));
    try!(output.write_u32::<LittleEndian>(4 * 3));

    try!(output.write_u32::<LittleEndian>(data.len() as u32));

    for corr_record in data {
        let record = corr_record.series;
        try!(output.write_u32::<LittleEndian>(record.data.len() as u32));
        try!(output.write_u32::<LittleEndian>(record.name.len() as u32));
        try!(output.write_f32::<LittleEndian>(corr_record.correlation as f32));
        try!(output.write(&record.name.as_bytes()));
        for i in 0..record.data.len() {
            try!(output.write_i32::<LittleEndian>(record.data[i].t));
            try!(output.write_f32::<LittleEndian>(record.data[i].val));
        }
    }
    Ok(())
}
<commit_msg>Convert from try to ?<commit_after>use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::cmp::Ordering;
use std::io::*;
use std::str;

#[derive(PartialEq, PartialOrd, Clone, Debug)]
pub struct Point {
    pub t: i32,
    pub val: f32,
}
impl Eq for Point {}
impl Ord for Point {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[derive(PartialEq, PartialOrd, Eq, Ord, Clone, Debug)]
pub struct BinaryTimeSeries {
    pub name: String,
    pub data: Vec<Point>,
}

#[derive(Clone, PartialEq)]
pub struct CorrelatedTimeSeries<'a> {
    pub series: &'a BinaryTimeSeries,
    pub correlation: f32,
}
impl<'a> PartialOrd for CorrelatedTimeSeries<'a> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        other.correlation.partial_cmp(&self.correlation)
    }
}

pub fn read_btsf_file<T: Read + Seek>(
    f: &mut T,
    series: &mut Vec<BinaryTimeSeries>,
) -> Result<usize> {
    f.seek(SeekFrom::Start(0))?;
    let _ = f.read_u32::<LittleEndian>()?;
    let file_header_len = f.read_u32::<LittleEndian>()?;
    let rec_header_len = f.read_u32::<LittleEndian>()?;
    let num_records = f.read_u32::<LittleEndian>()?;

    f.seek(SeekFrom::Start(file_header_len as u64))?;

    // println!("Version Number: {}", version);
    // println!("File Header Len: {}", file_header_len);
    // println!("Rec Header Len: {}", rec_header_len);
    // println!("Num Records: {}", num_records);

    series.reserve(num_records as usize);
    for _ in 0..num_records {
        let n = f.read_u32::<LittleEndian>()?;
        let name_length = f.read_u32::<LittleEndian>()?;
        f.seek(SeekFrom::Current((rec_header_len - 8) as i64))?; // Skip padding bytes;

        let mut buffer = [0; 1024];
        f.take(name_length as u64).read(&mut buffer)?;

        let name = match str::from_utf8(&buffer[0..(name_length as usize)]) {
            Ok(s) => s,
            Err(_) => return Err(Error::new(ErrorKind::InvalidInput, "Invalid input UTF-8")),
        };

        let mut data = Vec::<Point>::new();

        for _ in 0..n {
            let t = f.read_i32::<LittleEndian>()?;
            let d = f.read_f32::<LittleEndian>()?;
            data.push(Point { t: t, val: d });
        }
        series.push(BinaryTimeSeries {
            name: String::from(name),
            data: data,
        })
    }

    return Ok(num_records as usize);
}

pub fn write_btsf_file<T: Write>(data: &[&BinaryTimeSeries], output: &mut T) -> Result<()> {
    // Version Header, File Header Len, Rec Header Len
    output.write_u32::<LittleEndian>(2)?;
    output.write_u32::<LittleEndian>(4 * 4)?;
    output.write_u32::<LittleEndian>(4 * 2)?;

    output.write_u32::<LittleEndian>(data.len() as u32)?;

    for record in data {
        output.write_u32::<LittleEndian>(record.data.len() as u32)?;
        output.write_u32::<LittleEndian>(record.name.len() as u32)?;
        output.write(&record.name.as_bytes())?;
        for i in 0..record.data.len() {
            output.write_i32::<LittleEndian>(record.data[i].t)?;
            output.write_f32::<LittleEndian>(record.data[i].val)?;
        }
    }
    Ok(())
}

pub fn write_correlated_btsf_file<T: Write>(
    data: &[CorrelatedTimeSeries],
    output: &mut T,
) -> Result<()> {
    // Version Header, File Header Len, Rec Header Len
    output.write_u32::<LittleEndian>(2)?;
    output.write_u32::<LittleEndian>(4 * 4)?;
    output.write_u32::<LittleEndian>(4 * 3)?;

    output.write_u32::<LittleEndian>(data.len() as u32)?;

    for corr_record in data {
        let record = corr_record.series;
        output.write_u32::<LittleEndian>(record.data.len() as u32)?;
        output.write_u32::<LittleEndian>(record.name.len() as u32)?;
        output.write_f32::<LittleEndian>(corr_record.correlation as f32)?;
        output.write(&record.name.as_bytes())?;
        for i in 0..record.data.len() {
            output.write_i32::<LittleEndian>(record.data[i].t)?;
            output.write_f32::<LittleEndian>(record.data[i].val)?;
        }
    }
    Ok(())
}
<|endoftext|>