<commit_before>use std::slice::from_raw_parts;
use std::ffi::CStr;
use std::mem::copy_lifetime;
use libc;

use htslib;

#[derive(Debug)]
pub enum Aux<'a> {
    Integer(i32),
    String(&'a [u8]),
    Float(f64),
    Char(u8),
}

impl<'a> Aux<'a> {
    pub fn string(&self) -> &'a [u8] {
        match *self {
            Aux::String(x) => x,
            _ => panic!("not a string"),
        }
    }

    pub fn float(&self) -> f64 {
        match *self {
            Aux::Float(x) => x,
            _ => panic!("not a float"),
        }
    }

    pub fn integer(&self) -> i32 {
        match *self {
            Aux::Integer(x) => x,
            _ => panic!("not an integer"),
        }
    }

    pub fn char(&self) -> u8 {
        match *self {
            Aux::Char(x) => x,
            _ => panic!("not a character"),
        }
    }
}

pub struct Record {
    b: htslib::bam1_t,
}

impl Record {
    pub fn new() -> Self {
        let b = unsafe { *htslib::bam_init1() };
        Record { b: b }
    }
    // TODO ensure that owning b really destroys b.data when object goes out of scope

    fn data(&self) -> &[u8] {
        unsafe { from_raw_parts(self.b.data, self.b.l_data as usize) }
    }

    pub fn tid(&self) -> i32 {
        self.b.core.tid
    }

    pub fn pos(&self) -> i32 {
        self.b.core.pos
    }

    pub fn bin(&self) -> u16 {
        self.b.core.bin
    }

    pub fn map_qual(&self) -> u8 {
        self.b.core.qual
    }

    pub fn flag(&self) -> u16 {
        self.b.core.flag
    }

    pub fn mtid(&self) -> i32 {
        self.b.core.mtid
    }

    pub fn mpos(&self) -> i32 {
        self.b.core.mpos
    }

    pub fn isize(&self) -> i32 {
        self.b.core.isize
    }

    fn qname_len(&self) -> usize {
        self.b.core.l_qname as usize
    }

    pub fn qname(&self) -> &[u8] {
        &self.data()[..self.qname_len()-1] // -1 ignores the termination symbol

    }

    fn cigar_len(&self) -> usize {
        self.b.core.n_cigar as usize
    }

    pub fn cigar(&self) -> Vec<Cigar> {
        let raw = unsafe { from_raw_parts(self.data()[self.qname_len()..].as_ptr() as *const u32, self.cigar_len()) };
        raw.iter().map(|&c| {
            let len = c >> 4;
            match c & 0b1111 {
                0 => Cigar::Match(len),
                1 => Cigar::Ins(len),
                2 => Cigar::Del(len),
                3 => Cigar::RefSkip(len),
                4 => Cigar::SoftClip(len),
                5 => Cigar::HardClip(len),
                6 => Cigar::Pad(len),
                7 => Cigar::Equal(len),
                8 => Cigar::Diff(len),
                9 => Cigar::Back(len),
                _ => panic!("Unexpected cigar type"),
            }
        }).collect()
    }

    fn seq_len(&self) -> usize {
        self.b.core.l_qseq as usize
    }

    pub fn seq(&self) -> Seq {
        Seq {
            encoded: &self.data()
                        [self.qname_len() + self.cigar_len()*4..]
                        [..(self.seq_len() + 1) / 2]
        }
    }

    pub fn qual(&self) -> &[u8] {
        &self.data()[self.qname_len() + self.cigar_len()*4 + (self.seq_len()+1)/2..][..self.seq_len()]
    }

    pub fn aux(&self, name: &[u8]) -> Option<Aux> {
        let aux = unsafe { htslib::bam_aux_get(&self.b, name.as_ptr() as *mut i8 ) };

        unsafe {
            match *aux {
                b'c'|b'C'|b's'|b'S'|b'i'|b'I' => Some(Aux::Integer(htslib::bam_aux2i(aux))),
                b'f'|b'd' => Some(Aux::Float(htslib::bam_aux2f(aux))),
                b'A' => Some(Aux::Char(htslib::bam_aux2A(aux) as u8)),
                b'Z'|b'H' => {
                    let f = aux.offset(1) as *const i8;
                    let x = CStr::from_ptr(f).to_bytes();
                    Some(Aux::String(copy_lifetime(self, x)))
                },
                _ => None,
            }
        }
    }

    pub fn is_paired(&self) -> bool{
        (self.flag() & 1u16) > 0
    }

    pub fn is_proper_pair(&self) -> bool{
        (self.flag() & 2u16) > 0
    }

    pub fn is_unmapped(&self) -> bool{
        (self.flag() & 4u16) > 0
    }

    pub fn mate_is_unmapped(&self) -> bool{
        (self.flag() & 8u16) > 0
    }

    pub fn is_reverse(&self) -> bool{
        (self.flag() & 16u16) > 0
    }

    pub fn mate_is_reverse(&self) -> bool{
        (self.flag() & 32u16) > 0
    }

    pub fn is_first_in_pair(&self) -> bool{
        (self.flag() & 64u16) > 0
    }

    pub fn is_second_in_pair(&self) -> bool{
        (self.flag() & 128u16) > 0
    }

    pub fn is_secondary(&self) -> bool{
        (self.flag() & 256u16) > 0
    }

    pub fn is_quality_check_failed(&self) -> bool{
        (self.flag() & 512u16) > 0
    }

    pub fn is_duplicate(&self) -> bool{
        (self.flag() & 1024u16) > 0
    }

    pub fn is_supplementary(&self) -> bool{
        (self.flag() & 2048u16) > 0
    }
}

impl Drop for Record {
    fn drop(&mut self) {
        unsafe { libc::funcs::c95::stdlib::free(self.b.data as *mut libc::types::common::c95::c_void) };
    }
}

pub struct Bamfile {
    f: *mut htslib::Struct_BGZF,
    header: *mut htslib::bam_hdr_t,
}

impl Bamfile{
     pub fn new(filename: &[u8]) -> Self {
        let f = unsafe { htslib::bgzf_open(filename.as_ptr() as *const i8, b"r\0".as_ptr() as *const i8) };
        let header = unsafe { htslib::bam_hdr_read(f) };
        Bamfile { f : f, header : header }
    }

    pub fn read(&self, record: &mut Record) -> Result<(), Error> {
        match unsafe { htslib::bam_read1(self.f, &mut record.b as *mut htslib::bam1_t) } {
            -1 => Err(Error::EOF),
            -2 => Err(Error::Truncated),
            -4 => Err(Error::Invalid),
            _  => Ok(())
        }
    }

    pub fn records(self) -> Records {
        Records { bam: self }
    }
}

impl Drop for Bamfile {
    fn drop(&mut self) {
        unsafe {
            htslib::bam_hdr_destroy(self.header);
            htslib::bgzf_close(self.f);
        }
    }
}

pub struct Records {
    bam: Bamfile
}

impl Iterator for Records {
    type Item = Result<Record, Error>;

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

static TRANSLATE_BASE: &'static [u8] = b"=ACMGRSVTWYHKDBN";

pub struct Seq<'a> {
    pub encoded: &'a [u8]
}

impl<'a> Seq<'a> {

    #[inline]
    pub fn encoded_base(&self, i: usize) -> u8 {
        (self.encoded[i / 2] >> ((! i & 1) << 2)) & 0b1111
    }

    #[inline]
    pub fn base(&self, i: usize) -> u8 {
        TRANSLATE_BASE[self.encoded_base(i) as usize]
    }

    pub fn as_bytes(&self) -> Vec<u8> {
        (0..self.len()).map(|i| self.base(i)).collect()
    }

    pub fn len(&self) -> usize {
        self.encoded.len() * 2
    }
}

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Cigar {
    Match(u32),  // M
    Ins(u32),  // I
    Del(u32),  // D
    RefSkip(u32),  // N
    SoftClip(u32),  // S
    HardClip(u32),  // H
    Pad(u32),  // P
    Equal(u32),  // =
    Diff(u32),  // X
    Back(u32)  // B
}

pub enum Error {
    Truncated,
    Invalid,
    EOF,
}

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

    #[test]
    fn test_record() {
        let names = [b"I", b"II.14978392", b"III", b"IV", b"V", b"VI"];
        let flags = [16u16, 16u16, 16u16, 16u16, 16u16, 2048u16];
        let seqs = [
            b"CCTAGCCCTAACCCTAACCCTAACCCTAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAA",
            b"CCTAGCCCTAACCCTAACCCTAACCCTAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAA",
            b"CCTAGCCCTAACCCTAACCCTAACCCTAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAA",
            b"CCTAGCCCTAACCCTAACCCTAACCCTAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAA",
            b"CCTAGCCCTAACCCTAACCCTAACCCTAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAA",
            b"ACTAAGCCTAAGCCTAAGCCTAAGCCAATTATCGATTTCTGAAAAAATTATCGAATTTTCTAGAAATTTTGCAAATTTTTTCATAAAATTATCGATTTTA",
        ];
        let cigars = [
            [Cigar::Match(27), Cigar::Del(1), Cigar::Match(73)],
            [Cigar::Match(27), Cigar::Del(1), Cigar::Match(73)],
            [Cigar::Match(27), Cigar::Del(1), Cigar::Match(73)],
            [Cigar::Match(27), Cigar::Del(1), Cigar::Match(73)],
            [Cigar::Match(27), Cigar::Del(1), Cigar::Match(73)],
            [Cigar::Match(27), Cigar::Del(100000), Cigar::Match(73)],
        ];

        let bam = Bamfile::new(b"test.bam");

        for (i, record) in bam.records().enumerate() {
            let rec = record.ok().expect("Expected valid record");
            println!("{}", str::from_utf8(rec.qname()).ok().unwrap());
            assert_eq!(rec.qname(), names[i]);
            assert_eq!(rec.flag(), flags[i]);
            assert_eq!(rec.seq().as_bytes(), seqs[i]);
            assert_eq!(rec.cigar(), cigars[i]);
        }

    }
}
<commit_msg>Remove TODO.<commit_after>use std::slice::from_raw_parts;
use std::ffi::CStr;
use std::mem::copy_lifetime;
use libc;

use htslib;

#[derive(Debug)]
pub enum Aux<'a> {
    Integer(i32),
    String(&'a [u8]),
    Float(f64),
    Char(u8),
}

impl<'a> Aux<'a> {
    pub fn string(&self) -> &'a [u8] {
        match *self {
            Aux::String(x) => x,
            _ => panic!("not a string"),
        }
    }

    pub fn float(&self) -> f64 {
        match *self {
            Aux::Float(x) => x,
            _ => panic!("not a float"),
        }
    }

    pub fn integer(&self) -> i32 {
        match *self {
            Aux::Integer(x) => x,
            _ => panic!("not an integer"),
        }
    }

    pub fn char(&self) -> u8 {
        match *self {
            Aux::Char(x) => x,
            _ => panic!("not a character"),
        }
    }
}

pub struct Record {
    b: htslib::bam1_t,
}

impl Record {
    pub fn new() -> Self {
        let b = unsafe { *htslib::bam_init1() };
        Record { b: b }
    }

    fn data(&self) -> &[u8] {
        unsafe { from_raw_parts(self.b.data, self.b.l_data as usize) }
    }

    pub fn tid(&self) -> i32 {
        self.b.core.tid
    }

    pub fn pos(&self) -> i32 {
        self.b.core.pos
    }

    pub fn bin(&self) -> u16 {
        self.b.core.bin
    }

    pub fn map_qual(&self) -> u8 {
        self.b.core.qual
    }

    pub fn flag(&self) -> u16 {
        self.b.core.flag
    }

    pub fn mtid(&self) -> i32 {
        self.b.core.mtid
    }

    pub fn mpos(&self) -> i32 {
        self.b.core.mpos
    }

    pub fn isize(&self) -> i32 {
        self.b.core.isize
    }

    fn qname_len(&self) -> usize {
        self.b.core.l_qname as usize
    }

    pub fn qname(&self) -> &[u8] {
        &self.data()[..self.qname_len()-1] // -1 ignores the termination symbol

    }

    fn cigar_len(&self) -> usize {
        self.b.core.n_cigar as usize
    }

    pub fn cigar(&self) -> Vec<Cigar> {
        let raw = unsafe { from_raw_parts(self.data()[self.qname_len()..].as_ptr() as *const u32, self.cigar_len()) };
        raw.iter().map(|&c| {
            let len = c >> 4;
            match c & 0b1111 {
                0 => Cigar::Match(len),
                1 => Cigar::Ins(len),
                2 => Cigar::Del(len),
                3 => Cigar::RefSkip(len),
                4 => Cigar::SoftClip(len),
                5 => Cigar::HardClip(len),
                6 => Cigar::Pad(len),
                7 => Cigar::Equal(len),
                8 => Cigar::Diff(len),
                9 => Cigar::Back(len),
                _ => panic!("Unexpected cigar type"),
            }
        }).collect()
    }

    fn seq_len(&self) -> usize {
        self.b.core.l_qseq as usize
    }

    pub fn seq(&self) -> Seq {
        Seq {
            encoded: &self.data()
                        [self.qname_len() + self.cigar_len()*4..]
                        [..(self.seq_len() + 1) / 2]
        }
    }

    pub fn qual(&self) -> &[u8] {
        &self.data()[self.qname_len() + self.cigar_len()*4 + (self.seq_len()+1)/2..][..self.seq_len()]
    }

    pub fn aux(&self, name: &[u8]) -> Option<Aux> {
        let aux = unsafe { htslib::bam_aux_get(&self.b, name.as_ptr() as *mut i8 ) };

        unsafe {
            match *aux {
                b'c'|b'C'|b's'|b'S'|b'i'|b'I' => Some(Aux::Integer(htslib::bam_aux2i(aux))),
                b'f'|b'd' => Some(Aux::Float(htslib::bam_aux2f(aux))),
                b'A' => Some(Aux::Char(htslib::bam_aux2A(aux) as u8)),
                b'Z'|b'H' => {
                    let f = aux.offset(1) as *const i8;
                    let x = CStr::from_ptr(f).to_bytes();
                    Some(Aux::String(copy_lifetime(self, x)))
                },
                _ => None,
            }
        }
    }

    pub fn is_paired(&self) -> bool{
        (self.flag() & 1u16) > 0
    }

    pub fn is_proper_pair(&self) -> bool{
        (self.flag() & 2u16) > 0
    }

    pub fn is_unmapped(&self) -> bool{
        (self.flag() & 4u16) > 0
    }

    pub fn mate_is_unmapped(&self) -> bool{
        (self.flag() & 8u16) > 0
    }

    pub fn is_reverse(&self) -> bool{
        (self.flag() & 16u16) > 0
    }

    pub fn mate_is_reverse(&self) -> bool{
        (self.flag() & 32u16) > 0
    }

    pub fn is_first_in_pair(&self) -> bool{
        (self.flag() & 64u16) > 0
    }

    pub fn is_second_in_pair(&self) -> bool{
        (self.flag() & 128u16) > 0
    }

    pub fn is_secondary(&self) -> bool{
        (self.flag() & 256u16) > 0
    }

    pub fn is_quality_check_failed(&self) -> bool{
        (self.flag() & 512u16) > 0
    }

    pub fn is_duplicate(&self) -> bool{
        (self.flag() & 1024u16) > 0
    }

    pub fn is_supplementary(&self) -> bool{
        (self.flag() & 2048u16) > 0
    }
}

impl Drop for Record {
    fn drop(&mut self) {
        unsafe { libc::funcs::c95::stdlib::free(self.b.data as *mut libc::types::common::c95::c_void) };
    }
}

pub struct Bamfile {
    f: *mut htslib::Struct_BGZF,
    header: *mut htslib::bam_hdr_t,
}

impl Bamfile{
     pub fn new(filename: &[u8]) -> Self {
        let f = unsafe { htslib::bgzf_open(filename.as_ptr() as *const i8, b"r\0".as_ptr() as *const i8) };
        let header = unsafe { htslib::bam_hdr_read(f) };
        Bamfile { f : f, header : header }
    }

    pub fn read(&self, record: &mut Record) -> Result<(), Error> {
        match unsafe { htslib::bam_read1(self.f, &mut record.b as *mut htslib::bam1_t) } {
            -1 => Err(Error::EOF),
            -2 => Err(Error::Truncated),
            -4 => Err(Error::Invalid),
            _  => Ok(())
        }
    }

    pub fn records(self) -> Records {
        Records { bam: self }
    }
}

impl Drop for Bamfile {
    fn drop(&mut self) {
        unsafe {
            htslib::bam_hdr_destroy(self.header);
            htslib::bgzf_close(self.f);
        }
    }
}

pub struct Records {
    bam: Bamfile
}

impl Iterator for Records {
    type Item = Result<Record, Error>;

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

static TRANSLATE_BASE: &'static [u8] = b"=ACMGRSVTWYHKDBN";

pub struct Seq<'a> {
    pub encoded: &'a [u8]
}

impl<'a> Seq<'a> {

    #[inline]
    pub fn encoded_base(&self, i: usize) -> u8 {
        (self.encoded[i / 2] >> ((! i & 1) << 2)) & 0b1111
    }

    #[inline]
    pub fn base(&self, i: usize) -> u8 {
        TRANSLATE_BASE[self.encoded_base(i) as usize]
    }

    pub fn as_bytes(&self) -> Vec<u8> {
        (0..self.len()).map(|i| self.base(i)).collect()
    }

    pub fn len(&self) -> usize {
        self.encoded.len() * 2
    }
}

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Cigar {
    Match(u32),  // M
    Ins(u32),  // I
    Del(u32),  // D
    RefSkip(u32),  // N
    SoftClip(u32),  // S
    HardClip(u32),  // H
    Pad(u32),  // P
    Equal(u32),  // =
    Diff(u32),  // X
    Back(u32)  // B
}

pub enum Error {
    Truncated,
    Invalid,
    EOF,
}

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

    #[test]
    fn test_record() {
        let names = [b"I", b"II.14978392", b"III", b"IV", b"V", b"VI"];
        let flags = [16u16, 16u16, 16u16, 16u16, 16u16, 2048u16];
        let seqs = [
            b"CCTAGCCCTAACCCTAACCCTAACCCTAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAA",
            b"CCTAGCCCTAACCCTAACCCTAACCCTAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAA",
            b"CCTAGCCCTAACCCTAACCCTAACCCTAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAA",
            b"CCTAGCCCTAACCCTAACCCTAACCCTAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAA",
            b"CCTAGCCCTAACCCTAACCCTAACCCTAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAAGCCTAA",
            b"ACTAAGCCTAAGCCTAAGCCTAAGCCAATTATCGATTTCTGAAAAAATTATCGAATTTTCTAGAAATTTTGCAAATTTTTTCATAAAATTATCGATTTTA",
        ];
        let cigars = [
            [Cigar::Match(27), Cigar::Del(1), Cigar::Match(73)],
            [Cigar::Match(27), Cigar::Del(1), Cigar::Match(73)],
            [Cigar::Match(27), Cigar::Del(1), Cigar::Match(73)],
            [Cigar::Match(27), Cigar::Del(1), Cigar::Match(73)],
            [Cigar::Match(27), Cigar::Del(1), Cigar::Match(73)],
            [Cigar::Match(27), Cigar::Del(100000), Cigar::Match(73)],
        ];

        let bam = Bamfile::new(b"test.bam");

        for (i, record) in bam.records().enumerate() {
            let rec = record.ok().expect("Expected valid record");
            println!("{}", str::from_utf8(rec.qname()).ok().unwrap());
            assert_eq!(rec.qname(), names[i]);
            assert_eq!(rec.flag(), flags[i]);
            assert_eq!(rec.seq().as_bytes(), seqs[i]);
            assert_eq!(rec.cigar(), cigars[i]);
        }

    }
}
<|endoftext|>


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

#![allow(non_snake_case)]

use std;
use std::collections;
use std::io::prelude::*;
use std::error::Error;

use csv;
use itertools::Itertools;
use cue;
use regex::Regex;

use bio::stats::logprobs::Prob;
use bio::stats::logprobs;

use io;
use model;
use model::foldchange::LogFC;
use model::cv::CV;
use codebook;

pub struct Selection {
    pub expmnt: String,
    pub cell: String
}

#[derive(Debug)]
struct Counts {
    exact: u32,
    corrected: u32
}

/*pub fn stats(N: u8, m: u8, p0: Prob, p1: Prob, dist: u8, codebook_path: &str) {
    let codebook = io::codebook::Reader::from_file(codebook_path, dist).unwrap().codebook();
    let model = model::readout::new_model(N, m, p0, p1, dist, codebook);
    let mut reader = io::merfishdata::Reader::from_reader(std::io::stdin());

    let mut total_counts = collections::HashMap::new();
    for res in reader.records() {
        let record = res.unwrap();
        let total_count = total_counts.entry(record.cell_id).or_insert(0);
        *total_count += 1;
    }

    let mut writer = csv::Writer::from_writer(std::io::stdout()).delimiter(b'\t');
    writer.write(["cell", "total_expr_ev"].iter()).unwrap();

    for (cell, total_count) in total_counts {
        writer.write([cell, format!("{}", model.expected_total(total_count))].iter()).unwrap();
    }
}*/

/// Estimate expressions.
pub fn expression(N: u8, m: u8, p0: Prob, p1: Prob, dist: u8, codebook_path: &str, estimate_path: Option<&str>, threads: usize, cells: &str, window_width: u32) {
    let codebook = io::codebook::Reader::from_file(codebook_path, dist).unwrap().codebook();
    let model = model::readout::new_model(N, m, p0, p1, dist, codebook);
    let mut reader = io::merfishdata::Reader::from_reader(std::io::stdin());
    let mut cdf_writer = io::cdf::expression::Writer::from_writer(std::io::stdout());
    let mut est_writer = estimate_path.map(|path| io::estimation::expression::Writer::from_file(path));

    let cells = Regex::new(cells).ok().expect("Invalid regular expression for cells.");

    let mut counts = collections::HashMap::new();
    let mut features = collections::HashSet::new();
    for record in reader.records().filter_map(|res| {
            let rec = res.unwrap();
            features.insert(rec.feature.clone());
            if cells.is_match(&rec.cell_id) {
                Some(rec)
            }
            else {
                None
            }
        }
    ) {
        let cell_counts = counts.entry(record.cell_id).or_insert_with(collections::HashMap::new);
        let feature_counts = cell_counts.entry(record.feature).or_insert(Counts{ exact: 0, corrected: 0});
        if record.hamming_dist == 0 {
            feature_counts.exact += 1;
        }
        else if record.hamming_dist == 1 {
            feature_counts.corrected += 1;
        }
        else {
            panic!("Hamming distance of greater than 1 is unsupported at the moment.")
        }
    }
    for (_, cell_counts) in counts.iter_mut() {
        for feature in features.iter() {
            cell_counts.entry(feature.clone()).or_insert(Counts{ exact: 0, corrected: 0});
        }
    }

    cue::pipeline(
        "exp",
        threads,
        counts.into_iter(),
        |(cell, counts)| {
            let cdfs = counts.into_iter().map(|(feature, count)| {
                let cdf = model::expression::cdf(&feature, count.exact + count.corrected, count.exact, &model, window_width);
                (feature, cdf)
            }).collect_vec();
            (cell, cdfs)
        },
        |(cell, cdfs)| {
            for (feature, cdf) in cdfs {
                cdf_writer.write(&cell, &feature, &cdf);

                if let Some(ref mut est_writer) = est_writer {
                    est_writer.write(
                        &cell,
                        &feature,
                        cdf.expected_value(),
                        cdf.standard_deviation(),
                        *cdf.map(),
                        cdf.credible_interval()
                    );
                }
            }
        }
    );
}

/// Estimate differential expression over two conditions via fold changes.
pub fn differential_expression(group1_path: &str, group2_path: &str, pmf_path: Option<&str>, max_fc: LogFC, pseudocounts: f64, threads: usize) {
    assert!(pseudocounts > 0.0, "Pseudocounts must be > 0.0 for calculating fold changes.");

    let mut reader1 = io::cdf::expression::Reader::from_file(group1_path).expect("Invalid input for group 1.");
    let mut reader2 = io::cdf::expression::Reader::from_file(group2_path).expect("Invalid input for group 2.");
    let mut cdf_writer = pmf_path.map(|path| io::cdf::diffexp::Writer::from_file(path, "log2fc"));
    let mut est_writer = io::estimation::differential_expression::Writer::from_writer(std::io::stdout(), "log2fc");

    let group1 = reader1.cdfs();
    let group2 = reader2.cdfs();

    let features = group1.features().filter(|f| group2.contains_feature(f)).cloned().collect_vec();

    let mut estimates = Vec::new();

    cue::pipeline(
        "diffexp",
        threads,
        features.iter(),
        |feature| {
            info!("Calculating {}.", feature);
            let g1 = group1.get(&feature).unwrap();
            let g2 = group2.get(&feature).unwrap();
            let cdf = model::foldchange::cdf(
                &model::expressionset::cdf(&g1, pseudocounts),
                &model::expressionset::cdf(&g2, pseudocounts)
            );
            (feature, cdf)
        },
        |(feature, cdf)| {
            if cdf.iter().any(|&(_, prob)| prob.is_nan()) {
                warn!("A CDF probability for feature {} cannot be estimated because counts are too high. It will be reported as NaN.", feature);
            }

            if let Some(ref mut cdf_writer) = cdf_writer {
                cdf_writer.write(&feature, &cdf);
            }
            estimates.push((feature, cdf.estimate(max_fc)));
        }
    );

    // calculate FDR and write estimates to STDOUT
    estimates.sort_by(|&(_, ref a), &(_, ref b)| a.differential_expression_pep.partial_cmp(&b.differential_expression_pep).unwrap());
    let expected_fds = logprobs::cumsum(estimates.iter().map(|&(_, ref a)| a.differential_expression_pep)).collect_vec();
    for (i, ((feature, estimate), fd)) in estimates.into_iter().zip(expected_fds).enumerate() {
        let fdr = fd - (i as f64 + 1.0).ln();
        est_writer.write(
            &feature,
            estimate.differential_expression_pep,
            fdr,
            estimate.differential_expression_bf,
            estimate.expected_value,
            estimate.standard_deviation,
            estimate.credible_interval
        );
    }
}

/// Estimate differential expression over multiple conditions via the coefficient of variation.
pub fn multi_differential_expression(group_paths: &[&str], pmf_path: Option<&str>, max_cv: CV, pseudocounts: f64, threads: usize) {
    let groups = group_paths.iter().enumerate().map(|(i, path)| {
        io::cdf::expression::Reader::from_file(path).expect(&format!("Invalid input for group {}.", i))
                                                    .cdfs()
    }).collect_vec();
    let mut cdf_writer = pmf_path.map(|path| io::cdf::diffexp::Writer::from_file(path, "cv"));
    let mut est_writer = io::estimation::differential_expression::Writer::from_writer(std::io::stdout(), "cv");

    // TODO take feature intersection or warn if features are not the same
    let mut features = Vec::new();
    for feature in groups[0].features() {
        let mut common = true;
        for group in groups[1..].iter() {
            common &= group.contains_feature(feature);
        }
        if common {
            features.push(feature.clone());
        }
    }

    let mut estimates = Vec::new();

    cue::pipeline(
        "multidiffexp",
        threads,
        features.iter(),
        |feature| {
            info!("Calculating {}.", feature);
            let cdfs = groups.iter().map(|group| {
                model::expressionset::cdf(
                    group.get(&feature).expect("Missing feature."),
                    pseudocounts
                )
            }).collect_vec();
            let cdf = model::cv::cdf(&cdfs);
            (feature, cdf)
        },
        |(feature, cdf)| {
            if cdf.iter().any(|&(_, prob)| prob.is_nan()) {
                warn!("A CDF probability for feature {} cannot be estimated due to numerical problems. It will be reported as NaN.", feature);
            }

            if let Some(ref mut cdf_writer) = cdf_writer {
                cdf_writer.write(&feature, &cdf);
            }
            estimates.push((feature, cdf.estimate(max_cv)));
        }
    );

    // calculate FDR and write estimates to STDOUT
    estimates.sort_by(|&(_, ref a), &(_, ref b)| a.differential_expression_pep.partial_cmp(&b.differential_expression_pep).unwrap());
    let expected_fds = logprobs::cumsum(estimates.iter().map(|&(_, ref a)| a.differential_expression_pep)).collect_vec();
    for (i, ((feature, estimate), fd)) in estimates.into_iter().zip(expected_fds).enumerate() {
        let fdr = fd - (i as f64 + 1.0).ln();
        est_writer.write(
            &feature,
            estimate.differential_expression_pep,
            fdr,
            estimate.differential_expression_bf,
            estimate.expected_value,
            estimate.standard_deviation,
            estimate.credible_interval
        );
    }
}

pub fn gen_codebook(words: &[codebook::Word]) -> Result<(), Box<Error>> {
    let stdin = std::io::stdin();
    let mut reader = stdin.lock().lines();
    let mut writer = csv::Writer::from_writer(std::io::stdout()).delimiter(b'\t');
    let mut words = words.iter();
    writer.write(["feat", "codeword", "expressed"].iter()).unwrap();

    for i in 1.. {
        match (reader.next(), words.next()) {
            (Some(transcript), Some(w)) => {
                writer.write([try!(transcript), format!("{:?}", w), "1".to_owned()].into_iter()).unwrap();
            },
            (None, Some(_)) => break,
            (Some(_), None) => {
                error!("Not enough code words. Generated codebook for the first {} transcripts.", i);
                break
            },
            (None, None) => break
        }
    }
    Ok(())
}
<commit_msg>Add panic in case of empty feature.<commit_after>// Copyright 2016 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

use std;
use std::collections;
use std::io::prelude::*;
use std::error::Error;

use csv;
use itertools::Itertools;
use cue;
use regex::Regex;

use bio::stats::logprobs::Prob;
use bio::stats::logprobs;

use io;
use model;
use model::foldchange::LogFC;
use model::cv::CV;
use codebook;

pub struct Selection {
    pub expmnt: String,
    pub cell: String
}

#[derive(Debug)]
struct Counts {
    exact: u32,
    corrected: u32
}

/*pub fn stats(N: u8, m: u8, p0: Prob, p1: Prob, dist: u8, codebook_path: &str) {
    let codebook = io::codebook::Reader::from_file(codebook_path, dist).unwrap().codebook();
    let model = model::readout::new_model(N, m, p0, p1, dist, codebook);
    let mut reader = io::merfishdata::Reader::from_reader(std::io::stdin());

    let mut total_counts = collections::HashMap::new();
    for res in reader.records() {
        let record = res.unwrap();
        let total_count = total_counts.entry(record.cell_id).or_insert(0);
        *total_count += 1;
    }

    let mut writer = csv::Writer::from_writer(std::io::stdout()).delimiter(b'\t');
    writer.write(["cell", "total_expr_ev"].iter()).unwrap();

    for (cell, total_count) in total_counts {
        writer.write([cell, format!("{}", model.expected_total(total_count))].iter()).unwrap();
    }
}*/

/// Estimate expressions.
pub fn expression(N: u8, m: u8, p0: Prob, p1: Prob, dist: u8, codebook_path: &str, estimate_path: Option<&str>, threads: usize, cells: &str, window_width: u32) {
    let codebook = io::codebook::Reader::from_file(codebook_path, dist).unwrap().codebook();
    let model = model::readout::new_model(N, m, p0, p1, dist, codebook);
    let mut reader = io::merfishdata::Reader::from_reader(std::io::stdin());
    let mut cdf_writer = io::cdf::expression::Writer::from_writer(std::io::stdout());
    let mut est_writer = estimate_path.map(|path| io::estimation::expression::Writer::from_file(path));

    let cells = Regex::new(cells).ok().expect("Invalid regular expression for cells.");

    let mut counts = collections::HashMap::new();
    let mut features = collections::HashSet::new();
    for record in reader.records().filter_map(|res| {
            let rec = res.unwrap();
            features.insert(rec.feature.clone());
            if cells.is_match(&rec.cell_id) {
                Some(rec)
            }
            else {
                None
            }
        }
    ) {
        let cell_counts = counts.entry(record.cell_id).or_insert_with(collections::HashMap::new);
        let feature_counts = cell_counts.entry(record.feature).or_insert(Counts{ exact: 0, corrected: 0});
        if record.hamming_dist == 0 {
            feature_counts.exact += 1;
        }
        else if record.hamming_dist == 1 {
            feature_counts.corrected += 1;
        }
        else {
            panic!("Hamming distance of greater than 1 is unsupported at the moment.")
        }
    }
    for (_, cell_counts) in counts.iter_mut() {
        for feature in features.iter() {
            cell_counts.entry(feature.clone()).or_insert(Counts{ exact: 0, corrected: 0});
        }
    }

    cue::pipeline(
        "exp",
        threads,
        counts.into_iter(),
        |(cell, counts)| {
            let cdfs = counts.into_iter().map(|(feature, count)| {
                let cdf = model::expression::cdf(&feature, count.exact + count.corrected, count.exact, &model, window_width);
                (feature, cdf)
            }).collect_vec();
            (cell, cdfs)
        },
        |(cell, cdfs)| {
            for (feature, cdf) in cdfs {
                cdf_writer.write(&cell, &feature, &cdf);

                if let Some(ref mut est_writer) = est_writer {
                    est_writer.write(
                        &cell,
                        &feature,
                        cdf.expected_value(),
                        cdf.standard_deviation(),
                        *cdf.map(),
                        cdf.credible_interval()
                    );
                }
            }
        }
    );
}

/// Estimate differential expression over two conditions via fold changes.
pub fn differential_expression(group1_path: &str, group2_path: &str, pmf_path: Option<&str>, max_fc: LogFC, pseudocounts: f64, threads: usize) {
    assert!(pseudocounts > 0.0, "Pseudocounts must be > 0.0 for calculating fold changes.");

    let mut reader1 = io::cdf::expression::Reader::from_file(group1_path).expect("Invalid input for group 1.");
    let mut reader2 = io::cdf::expression::Reader::from_file(group2_path).expect("Invalid input for group 2.");
    let mut cdf_writer = pmf_path.map(|path| io::cdf::diffexp::Writer::from_file(path, "log2fc"));
    let mut est_writer = io::estimation::differential_expression::Writer::from_writer(std::io::stdout(), "log2fc");

    let group1 = reader1.cdfs();
    let group2 = reader2.cdfs();

    let features = group1.features().filter(|f| group2.contains_feature(f)).cloned().collect_vec();

    let mut estimates = Vec::new();

    cue::pipeline(
        "diffexp",
        threads,
        features.iter(),
        |feature| {
            info!("Calculating {}.", feature);
            let g1 = group1.get(&feature).unwrap();
            let g2 = group2.get(&feature).unwrap();
            let cdf = model::foldchange::cdf(
                &model::expressionset::cdf(&g1, pseudocounts),
                &model::expressionset::cdf(&g2, pseudocounts)
            );
            (feature, cdf)
        },
        |(feature, cdf)| {
            if cdf.iter().any(|&(_, prob)| prob.is_nan()) {
                warn!("A CDF probability for feature {} cannot be estimated because counts are too high. It will be reported as NaN.", feature);
            }

            if let Some(ref mut cdf_writer) = cdf_writer {
                cdf_writer.write(&feature, &cdf);
            }
            estimates.push((feature, cdf.estimate(max_fc)));
        }
    );

    // calculate FDR and write estimates to STDOUT
    estimates.sort_by(|&(_, ref a), &(_, ref b)| a.differential_expression_pep.partial_cmp(&b.differential_expression_pep).unwrap());
    let expected_fds = logprobs::cumsum(estimates.iter().map(|&(_, ref a)| a.differential_expression_pep)).collect_vec();
    for (i, ((feature, estimate), fd)) in estimates.into_iter().zip(expected_fds).enumerate() {
        let fdr = fd - (i as f64 + 1.0).ln();
        est_writer.write(
            &feature,
            estimate.differential_expression_pep,
            fdr,
            estimate.differential_expression_bf,
            estimate.expected_value,
            estimate.standard_deviation,
            estimate.credible_interval
        );
    }
}

/// Estimate differential expression over multiple conditions via the coefficient of variation.
pub fn multi_differential_expression(group_paths: &[&str], pmf_path: Option<&str>, max_cv: CV, pseudocounts: f64, threads: usize) {
    let groups = group_paths.iter().enumerate().map(|(i, path)| {
        io::cdf::expression::Reader::from_file(path).expect(&format!("Invalid input for group {}.", i))
                                                    .cdfs()
    }).collect_vec();
    let mut cdf_writer = pmf_path.map(|path| io::cdf::diffexp::Writer::from_file(path, "cv"));
    let mut est_writer = io::estimation::differential_expression::Writer::from_writer(std::io::stdout(), "cv");

    // TODO take feature intersection or warn if features are not the same
    let mut features = Vec::new();
    for feature in groups[0].features() {
        let mut common = true;
        for group in groups[1..].iter() {
            common &= group.contains_feature(feature);
        }
        if common {
            features.push(feature.clone());
        }
    }

    let mut estimates = Vec::new();

    cue::pipeline(
        "multidiffexp",
        threads,
        features.iter(),
        |feature| {
            info!("Calculating {}.", feature);
            let cdfs = groups.iter().map(|group| {
                model::expressionset::cdf(
                    group.get(&feature).expect("Missing feature."),
                    pseudocounts
                )
            }).collect_vec();
            let cdf = model::cv::cdf(&cdfs);
            (feature, cdf)
        },
        |(feature, cdf)| {
            if cdf.iter().any(|&(_, prob)| prob.is_nan()) {
                warn!("A CDF probability for feature {} cannot be estimated due to numerical problems. It will be reported as NaN.", feature);
            }

            if let Some(ref mut cdf_writer) = cdf_writer {
                cdf_writer.write(&feature, &cdf);
            }
            estimates.push((feature, cdf.estimate(max_cv)));
        }
    );

    // calculate FDR and write estimates to STDOUT
    estimates.sort_by(|&(_, ref a), &(_, ref b)| a.differential_expression_pep.partial_cmp(&b.differential_expression_pep).unwrap());
    let expected_fds = logprobs::cumsum(estimates.iter().map(|&(_, ref a)| a.differential_expression_pep)).collect_vec();
    for (i, ((feature, estimate), fd)) in estimates.into_iter().zip(expected_fds).enumerate() {
        let fdr = fd - (i as f64 + 1.0).ln();
        est_writer.write(
            &feature,
            estimate.differential_expression_pep,
            fdr,
            estimate.differential_expression_bf,
            estimate.expected_value,
            estimate.standard_deviation,
            estimate.credible_interval
        );
    }
}

pub fn gen_codebook(words: &[codebook::Word]) -> Result<(), Box<Error>> {
    let stdin = std::io::stdin();
    let mut reader = stdin.lock().lines();
    let mut writer = csv::Writer::from_writer(std::io::stdout()).delimiter(b'\t');
    let mut words = words.iter();
    writer.write(["feat", "codeword", "expressed"].iter()).unwrap();

    for i in 1.. {
        match (reader.next(), words.next()) {
            (Some(feature), Some(w)) => {
                let feature = try!(feature);
                if feature.len() == 0 {
                    // TODO proper error handling
                    panic!("Empty feature found. All features provided at STDIN have to be non-empty.");
                }
                writer.write([feature, format!("{:?}", w), "1".to_owned()].into_iter()).unwrap();
            },
            (None, Some(_)) => break,
            (Some(_), None) => {
                error!("Not enough code words. Generated codebook for the first {} transcripts.", i);
                break
            },
            (None, None) => break
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use rustc_serialize::Decodable;
use docopt;
use std::process;

use command;

const USAGE: &'static str = "
Slate.

Usage:
  slate <command> [<args>...]
  slate [options]

Options:
  -h --help      Show this screen.
  -v --version   Show version.

Commands:
   set     Write a new key and value.
   get     Read a key.
   list    List all keys.
   rename  Rename a key.
   remove  Delete a key.
   exec    Run a key value as a command.
   snippet Get a key and replace all placeholders with new data.
";

#[derive(Debug, RustcDecodable)]
enum Command {
    Set,
    Get,
    List,
    Remove,
    Rename,
    Exec,
    Snippet,
}

impl Command {
    fn run(self, argv: &Vec<String>) -> Result<Option<String>, &str> {
        match self {
            Command::Set => { command::set::run(argv) },
            Command::Get => { command::get::run(argv) },
            Command::List => { command::list::run(argv) },
            Command::Remove => { command::remove::run(argv) },
            Command::Rename => { command::rename::run(argv) },
            Command::Exec => { command::exec::run(argv) },
            Command::Snippet => { command::snippet::run(argv) },
        }
    }
}

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_command: Option<Command>,
    flag_help: bool,
    flag_version: bool,
}

pub fn run(argv: Vec<String>) {
    let args: Args = parse_main_args(USAGE, &argv).unwrap_or_else(|e| e.exit());

    let command = match args.arg_command {
        None => {
            println!("Noop!");
            process::exit(404); // NOTE: use consistent error codes
        },
        Some(command) => command,
    };

    match command.run(&argv) {
        Err(e) => error(e),
        Ok(message) => out(message),
    };
}

pub fn parse_args<T>(usage: &str, argv: &Vec<String>) -> Result<T, docopt::Error>
    where T: Decodable {
        docopt::Docopt::new(usage)
            .and_then(|d| d.argv(argv)
                           .version(Some(super::version()))
                           .decode())
}

fn parse_main_args<T>(usage: &str, argv: &Vec<String>) -> Result<T, docopt::Error>
    where T: Decodable {
        docopt::Docopt::new(usage)
            .and_then(|d| d.argv(argv)
                           .options_first(true)
                           .version(Some(super::version()))
                           .decode())
}

fn error(err: &str) {
    println!("{}", err);
    process::exit(1);
}

fn out(message: Option<String>) {
    if let Some(msg) = message {
        println!("{}", msg);
    };
    process::exit(0);
}
<commit_msg>Parsing arguments with Option<Command> doesn't work as expected.<commit_after>use rustc_serialize::Decodable;
use docopt;
use std::process;

use command;

const USAGE: &'static str = "
Slate.

Usage:
  slate <command> [<args>...]
  slate [options]

Options:
  -h --help      Show this screen.
  -v --version   Show version.

Commands:
   set     Write a new key and value.
   get     Read a key.
   list    List all keys.
   rename  Rename a key.
   remove  Delete a key.
   exec    Run a key value as a command.
   snippet Get a key and replace all placeholders with new data.
";

#[derive(Debug, RustcDecodable)]
enum Command {
    Set,
    Get,
    List,
    Remove,
    Rename,
    Exec,
    Snippet,
}

impl Command {
    fn run(self, argv: &Vec<String>) -> Result<Option<String>, &str> {
        match self {
            Command::Set => { command::set::run(argv) },
            Command::Get => { command::get::run(argv) },
            Command::List => { command::list::run(argv) },
            Command::Remove => { command::remove::run(argv) },
            Command::Rename => { command::rename::run(argv) },
            Command::Exec => { command::exec::run(argv) },
            Command::Snippet => { command::snippet::run(argv) },
        }
    }
}

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_command: Command,
    flag_help: bool,
    flag_version: bool,
}

pub fn run(argv: Vec<String>) {
    let args: Args = parse_main_args(USAGE, &argv).unwrap_or_else(|e| e.exit());

    let command = args.arg_command;

    match command.run(&argv) {
        Err(e) => error(e),
        Ok(message) => out(message),
    };
}

pub fn parse_args<T>(usage: &str, argv: &Vec<String>) -> Result<T, docopt::Error>
    where T: Decodable {
        docopt::Docopt::new(usage)
            .and_then(|d| d.argv(argv)
                           .version(Some(super::version()))
                           .decode())
}

fn parse_main_args<T>(usage: &str, argv: &Vec<String>) -> Result<T, docopt::Error>
    where T: Decodable {
        docopt::Docopt::new(usage)
            .and_then(|d| d.argv(argv)
                           .options_first(true)
                           .version(Some(super::version()))
                           .decode())
}

fn error(err: &str) {
    println!("{}", err);
    process::exit(1);
}

fn out(message: Option<String>) {
    if let Some(msg) = message {
        println!("{}", msg);
    };
    process::exit(0);
}
<|endoftext|>


<commit_before>/// Module encapsules all command constants.
macro_rules! commands {
    {$(
        $ident:ident
        #[$doc:meta];
    )*} => {
        /// Enumeration of all supported IRC commands (mainly RFC1459)
        #[deriving(Show, PartialEq)]
        pub enum Command<'a> {
            $(#[$doc] $ident,)*
            /// Numeric reply codes, see `ResponseCode`
            REPLY(ResponseCode),
            /// Catch all unknown/unsupported commands
            UNKNOWN(&'a[u8]),
        }

        impl<'a> Command<'a> {
            /// Converts bytestring to Command
            pub fn from_bytes(bytes: &'a [u8]) -> Command<'a> {
                // TODO add REPLY(...)
                $(if bytes == stringify!($ident).as_bytes() { $ident } else)* {
                    UNKNOWN(bytes)
                }
            }

            /// Converts the command into bytes
            pub fn to_bytes(&'a self) -> Vec<u8> {
                match *self {
                    $($ident => Vec::from_slice(stringify!($ident).as_bytes()),)*
                    REPLY(reply) => format!("{:03u}", reply as u16).into_bytes(),
                    UNKNOWN(bytes) => Vec::from_slice(bytes)
                }
            }

            /// Converts the command into a string
            pub fn to_string(&'a self) -> String {
                String::from_utf8_lossy(self.to_bytes().as_slice()).into_string()
            }
        }
    }
}

commands!{
    PRIVMSG     #[doc = "`PRIVMSG` command"];
    NOTICE      #[doc = "`NOTICE` command"];
    MODE        #[doc = "`MODE` command"];
    JOIN        #[doc = "`JOIN` command, see http://tools.ietf.org/html/rfc1459.html#section-4.2.1"];
    PING        #[doc = "`PING` command"];
    WHO         #[doc = "`WHO` command"];
    NAMES       #[doc = "`NAMES` command"];
    TOPIC       #[doc = "`TOPIC` command"];
    PART        #[doc = "`PART` command"];
    QUIT        #[doc = "`QUIT` command"];
    PONG        #[doc = "`PONG` command"];
    NICK        #[doc = "`NICK` command"];
    USER        #[doc = "`USER` command"];
    CAP         #[doc = "`CAP` command"];
}

#[allow(non_camel_case_types)]
#[deriving(Show, PartialEq)]
pub enum ResponseCode {
    RPL_WELCOME = 001,
    RPL_YOURHOST = 002,
    RPL_CREATED = 003,
    RPL_MYINFO = 004,
    RPL_BOUNCE = 005,
    RPL_USERHOST = 302,
    RPL_ISON = 303,
    RPL_AWAY = 301,
    RPL_UNAWAY = 305,
    RPL_NOWAWAY = 306,
    RPL_WHOISUSER = 311,
    RPL_WHOISSERVER = 312,
    RPL_WHOISOPERATOR = 313,
    RPL_WHOISIDLE = 317,
    RPL_ENDOFWHOIS = 318,
    RPL_WHOISCHANNELS = 319,
    RPL_WHOWASUSER = 314,
    RPL_ENDOFWHOWAS = 369,
    RPL_LISTSTART = 321,
    RPL_LIST = 322,
    RPL_LISTEND = 323,
    RPL_UNIQOPIS = 325,
    RPL_CHANNELMODEIS = 324,
    RPL_NOTOPIC = 331,
    RPL_TOPIC = 332,
    RPL_INVITING = 341,
    RPL_SUMMONING = 342,
    RPL_INVITELIST = 346,
    RPL_ENDOFINVITELIST = 347,
    RPL_EXCEPTLIST = 348,
    RPL_ENDOFEXCEPTLIST = 349,
    RPL_VERSION = 351,
    RPL_WHOREPLY = 352,
    RPL_ENDOFWHO = 315,
    RPL_NAMREPLY = 353,
    RPL_ENDOFNAMES = 366,
    RPL_LINKS = 364,
    RPL_ENDOFLINKS = 365,
    RPL_BANLIST = 367,
    RPL_ENDOFBANLIST = 368,
    RPL_INFO = 371,
    RPL_ENDOFINFO = 374,
    RPL_MOTDSTART = 375,
    RPL_MOTD = 372,
    RPL_ENDOFMOTD = 376,
    RPL_YOUREOPER = 381,
    RPL_REHASHING = 382,
    RPL_YOURESERVICE = 383,
    RPL_TIME = 391,
    RPL_USERSSTART = 392,
    RPL_USERS = 393,
    RPL_ENDOFUSERS = 394,
    RPL_NOUSERS = 395,
    RPL_TRACELINK = 200,
    RPL_TRACECONNECTING = 201,
    RPL_TRACEHANDSHAKE = 202,
    RPL_TRACEUNKNOWN = 203,
    RPL_TRACEOPERATOR = 204,
    RPL_TRACEUSER = 205,
    RPL_TRACESERVER = 206,
    RPL_TRACESERVICE = 207,
    RPL_TRACENEWTYPE = 208,
    RPL_TRACECLASS = 209,
    RPL_TRACERECONNECT = 210,
    RPL_TRACELOG = 261,
    RPL_TRACEEND = 262,
    RPL_STATSLINKINFO = 211,
    RPL_STATSCOMMANDS = 212,
    RPL_ENDOFSTATS = 219,
    RPL_STATSUPTIME = 242,
    RPL_STATSOLINE = 243,
    RPL_UMODEIS = 221,
    RPL_SERVLIST = 234,
    RPL_SERVLISTEND = 235,
    RPL_LUSERCLIENT = 251,
    RPL_LUSEROP = 252,
    RPL_LUSERUNKNOWN = 253,
    RPL_LUSERCHANNELS = 254,
    RPL_LUSERME = 255,
    RPL_ADMINME = 256,
    RPL_ADMINLOC1 = 257,
    RPL_ADMINLOC2 = 258,
    RPL_ADMINEMAIL = 259,
    RPL_TRYAGAIN = 263,
    ERR_NOSUCHNICK = 401,
    ERR_NOSUCHSERVER = 402,
    ERR_NOSUCHCHANNEL = 403,
    ERR_CANNOTSENDTOCHAN = 404,
    ERR_TOOMANYCHANNELS = 405,
    ERR_WASNOSUCHNICK = 406,
    ERR_TOOMANYTARGETS = 407,
    ERR_NOSUCHSERVICE = 408,
    ERR_NOORIGIN = 409,
    ERR_NORECIPIENT = 411,
    ERR_NOTEXTTOSEND = 412,
    ERR_NOTOPLEVEL = 413,
    ERR_WILDTOPLEVEL = 414,
    ERR_BADMASK = 415,
    ERR_UNKNOWNCOMMAND = 421,
    ERR_NOMOTD = 422,
    ERR_NOADMININFO = 423,
    ERR_FILEERROR = 424,
    ERR_NONICKNAMEGIVEN = 431,
    ERR_ERRONEUSNICKNAME = 432,
    ERR_NICKNAMEINUSE = 433,
    ERR_NICKCOLLISION = 436,
    ERR_UNAVAILRESOURCE = 437,
    ERR_USERNOTINCHANNEL = 441,
    ERR_NOTONCHANNEL = 442,
    ERR_USERONCHANNEL = 443,
    ERR_NOLOGIN = 444,
    ERR_SUMMONDISABLED = 445,
    ERR_USERSDISABLED = 446,
    ERR_NOTREGISTERED = 451,
    ERR_NEEDMOREPARAMS = 461,
    ERR_ALREADYREGISTRED = 462,
    ERR_NOPERMFORHOST = 463,
    ERR_PASSWDMISMATCH = 464,
    ERR_YOUREBANNEDCREEP = 465,
    ERR_YOUWILLBEBANNED = 466,
    ERR_KEYSET = 467,
    ERR_CHANNELISFULL = 471,
    ERR_UNKNOWNMODE = 472,
    ERR_INVITEONLYCHAN = 473,
    ERR_BANNEDFROMCHAN = 474,
    ERR_BADCHANNELKEY = 475,
    ERR_BADCHANMASK = 476,
    ERR_NOCHANMODES = 477,
    ERR_BANLISTFULL = 478,
    ERR_NOPRIVILEGES = 481,
    ERR_CHANOPRIVSNEEDED = 482,
    ERR_CANTKILLSERVER = 483,
    ERR_RESTRICTED = 484,
    ERR_UNIQOPPRIVSNEEDED = 485,
    ERR_NOOPERHOST = 491,
    ERR_UMODEUNKNOWNFLAG = 501,
    ERR_USERSDONTMATCH = 502,
}<commit_msg>update to latest rust<commit_after>/// Module encapsules all command constants.
macro_rules! commands {
    {$(
        $ident:ident
        #[$doc:meta];
    )*} => {
        /// Enumeration of all supported IRC commands (mainly RFC1459)
        #[deriving(Show, PartialEq)]
        pub enum Command<'a> {
            $(#[$doc] $ident,)*
            /// Numeric reply codes, see `ResponseCode`
            REPLY(ResponseCode),
            /// Catch all unknown/unsupported commands
            UNKNOWN(&'a[u8]),
        }

        impl<'a> Command<'a> {
            /// Converts bytestring to Command
            pub fn from_bytes(bytes: &'a [u8]) -> Command<'a> {
                // TODO add REPLY(...)
                $(if bytes == stringify!($ident).as_bytes() { $ident } else)* {
                    UNKNOWN(bytes)
                }
            }

            /// Converts the command into bytes
            pub fn to_bytes(&'a self) -> Vec<u8> {
                match *self {
                    $($ident => stringify!($ident).as_bytes().to_vec(),)*
                    REPLY(reply) => format!("{:03u}", reply as u16).into_bytes(),
                    UNKNOWN(bytes) => bytes.to_vec()
                }
            }

            /// Converts the command into a string
            pub fn to_string(&'a self) -> String {
                String::from_utf8_lossy(self.to_bytes().as_slice()).into_string()
            }
        }
    }
}

commands!{
    PRIVMSG     #[doc = "`PRIVMSG` command"];
    NOTICE      #[doc = "`NOTICE` command"];
    MODE        #[doc = "`MODE` command"];
    JOIN        #[doc = "`JOIN` command, see http://tools.ietf.org/html/rfc1459.html#section-4.2.1"];
    PING        #[doc = "`PING` command"];
    WHO         #[doc = "`WHO` command"];
    NAMES       #[doc = "`NAMES` command"];
    TOPIC       #[doc = "`TOPIC` command"];
    PART        #[doc = "`PART` command"];
    QUIT        #[doc = "`QUIT` command"];
    PONG        #[doc = "`PONG` command"];
    NICK        #[doc = "`NICK` command"];
    USER        #[doc = "`USER` command"];
    CAP         #[doc = "`CAP` command"];
}

#[allow(non_camel_case_types)]
#[deriving(Show, PartialEq)]
pub enum ResponseCode {
    RPL_WELCOME = 001,
    RPL_YOURHOST = 002,
    RPL_CREATED = 003,
    RPL_MYINFO = 004,
    RPL_BOUNCE = 005,
    RPL_USERHOST = 302,
    RPL_ISON = 303,
    RPL_AWAY = 301,
    RPL_UNAWAY = 305,
    RPL_NOWAWAY = 306,
    RPL_WHOISUSER = 311,
    RPL_WHOISSERVER = 312,
    RPL_WHOISOPERATOR = 313,
    RPL_WHOISIDLE = 317,
    RPL_ENDOFWHOIS = 318,
    RPL_WHOISCHANNELS = 319,
    RPL_WHOWASUSER = 314,
    RPL_ENDOFWHOWAS = 369,
    RPL_LISTSTART = 321,
    RPL_LIST = 322,
    RPL_LISTEND = 323,
    RPL_UNIQOPIS = 325,
    RPL_CHANNELMODEIS = 324,
    RPL_NOTOPIC = 331,
    RPL_TOPIC = 332,
    RPL_INVITING = 341,
    RPL_SUMMONING = 342,
    RPL_INVITELIST = 346,
    RPL_ENDOFINVITELIST = 347,
    RPL_EXCEPTLIST = 348,
    RPL_ENDOFEXCEPTLIST = 349,
    RPL_VERSION = 351,
    RPL_WHOREPLY = 352,
    RPL_ENDOFWHO = 315,
    RPL_NAMREPLY = 353,
    RPL_ENDOFNAMES = 366,
    RPL_LINKS = 364,
    RPL_ENDOFLINKS = 365,
    RPL_BANLIST = 367,
    RPL_ENDOFBANLIST = 368,
    RPL_INFO = 371,
    RPL_ENDOFINFO = 374,
    RPL_MOTDSTART = 375,
    RPL_MOTD = 372,
    RPL_ENDOFMOTD = 376,
    RPL_YOUREOPER = 381,
    RPL_REHASHING = 382,
    RPL_YOURESERVICE = 383,
    RPL_TIME = 391,
    RPL_USERSSTART = 392,
    RPL_USERS = 393,
    RPL_ENDOFUSERS = 394,
    RPL_NOUSERS = 395,
    RPL_TRACELINK = 200,
    RPL_TRACECONNECTING = 201,
    RPL_TRACEHANDSHAKE = 202,
    RPL_TRACEUNKNOWN = 203,
    RPL_TRACEOPERATOR = 204,
    RPL_TRACEUSER = 205,
    RPL_TRACESERVER = 206,
    RPL_TRACESERVICE = 207,
    RPL_TRACENEWTYPE = 208,
    RPL_TRACECLASS = 209,
    RPL_TRACERECONNECT = 210,
    RPL_TRACELOG = 261,
    RPL_TRACEEND = 262,
    RPL_STATSLINKINFO = 211,
    RPL_STATSCOMMANDS = 212,
    RPL_ENDOFSTATS = 219,
    RPL_STATSUPTIME = 242,
    RPL_STATSOLINE = 243,
    RPL_UMODEIS = 221,
    RPL_SERVLIST = 234,
    RPL_SERVLISTEND = 235,
    RPL_LUSERCLIENT = 251,
    RPL_LUSEROP = 252,
    RPL_LUSERUNKNOWN = 253,
    RPL_LUSERCHANNELS = 254,
    RPL_LUSERME = 255,
    RPL_ADMINME = 256,
    RPL_ADMINLOC1 = 257,
    RPL_ADMINLOC2 = 258,
    RPL_ADMINEMAIL = 259,
    RPL_TRYAGAIN = 263,
    ERR_NOSUCHNICK = 401,
    ERR_NOSUCHSERVER = 402,
    ERR_NOSUCHCHANNEL = 403,
    ERR_CANNOTSENDTOCHAN = 404,
    ERR_TOOMANYCHANNELS = 405,
    ERR_WASNOSUCHNICK = 406,
    ERR_TOOMANYTARGETS = 407,
    ERR_NOSUCHSERVICE = 408,
    ERR_NOORIGIN = 409,
    ERR_NORECIPIENT = 411,
    ERR_NOTEXTTOSEND = 412,
    ERR_NOTOPLEVEL = 413,
    ERR_WILDTOPLEVEL = 414,
    ERR_BADMASK = 415,
    ERR_UNKNOWNCOMMAND = 421,
    ERR_NOMOTD = 422,
    ERR_NOADMININFO = 423,
    ERR_FILEERROR = 424,
    ERR_NONICKNAMEGIVEN = 431,
    ERR_ERRONEUSNICKNAME = 432,
    ERR_NICKNAMEINUSE = 433,
    ERR_NICKCOLLISION = 436,
    ERR_UNAVAILRESOURCE = 437,
    ERR_USERNOTINCHANNEL = 441,
    ERR_NOTONCHANNEL = 442,
    ERR_USERONCHANNEL = 443,
    ERR_NOLOGIN = 444,
    ERR_SUMMONDISABLED = 445,
    ERR_USERSDISABLED = 446,
    ERR_NOTREGISTERED = 451,
    ERR_NEEDMOREPARAMS = 461,
    ERR_ALREADYREGISTRED = 462,
    ERR_NOPERMFORHOST = 463,
    ERR_PASSWDMISMATCH = 464,
    ERR_YOUREBANNEDCREEP = 465,
    ERR_YOUWILLBEBANNED = 466,
    ERR_KEYSET = 467,
    ERR_CHANNELISFULL = 471,
    ERR_UNKNOWNMODE = 472,
    ERR_INVITEONLYCHAN = 473,
    ERR_BANNEDFROMCHAN = 474,
    ERR_BADCHANNELKEY = 475,
    ERR_BADCHANMASK = 476,
    ERR_NOCHANMODES = 477,
    ERR_BANLISTFULL = 478,
    ERR_NOPRIVILEGES = 481,
    ERR_CHANOPRIVSNEEDED = 482,
    ERR_CANTKILLSERVER = 483,
    ERR_RESTRICTED = 484,
    ERR_UNIQOPPRIVSNEEDED = 485,
    ERR_NOOPERHOST = 491,
    ERR_UMODEUNKNOWNFLAG = 501,
    ERR_USERSDONTMATCH = 502,
}<|endoftext|>


<commit_before>use ::{ NifEnv, NifTerm };
use wrapper::copy_term;
use wrapper::nif_interface::{ self, NIF_ENV, NIF_TERM };
pub use wrapper::nif_interface::ErlNifPid;
use std::mem;
use std::sync::{Arc, Weak};

impl<'a> NifEnv<'a> {
    /// Return the calling process's pid.
    ///
    /// # Panics
    ///
    /// Panics if this environment is process-independent.  (The only way to get such an
    /// environment is to use `OwnedEnv`.  The `NifEnv` that Rustler passes to NIFs when they're
    /// called is always associated with the calling Erlang process.)
    pub fn pid(self) -> ErlNifPid {
        let mut pid: ErlNifPid = unsafe { mem::uninitialized() };
        if unsafe { nif_interface::enif_self(self.as_c_arg(), &mut pid) }.is_null() {
            panic!("environment is process-independent");
        }
        pid
    }
}

// Helper function used by save() and load().
unsafe fn nif_term_into_env<'a>(term: NIF_TERM, src_env: NIF_ENV, dest_env: NIF_ENV) -> NIF_TERM {
    if src_env == dest_env {
        term
    } else {
        copy_term(dest_env, term)
    }
}

/// A process-independent environment.
///
/// An owned environment is a place where Erlang terms can be created outside of a NIF call. Rust
/// code can use an owned environment to build a message and send it to an Erlang process.
///
///     use rustler::env::{OwnedEnv, ErlNifPid};
///     use rustler::NifEncoder;
///
///     fn send_string_to_pid(data: &str, pid: ErlNifPid) {
///         let mut msg_env = OwnedEnv::new();
///         msg_env.send(pid, |env| data.encode(env));
///     }
///
/// There's no way to run Erlang code in an owned environment. It's not a process. It's just a
/// workspace for building terms.
pub struct OwnedEnv {
    env: Arc<NIF_ENV>
}

unsafe impl Send for OwnedEnv {}

impl OwnedEnv {
    /// Allocates a new process-independent environment.
    pub fn new() -> OwnedEnv {
        OwnedEnv {
            env: Arc::new(unsafe { nif_interface::enif_alloc_env() })
        }
    }

    /// Run some code in this environment.
    pub fn run<F, R>(&self, closure: F) -> R
        where F: for<'a> FnOnce(NifEnv<'a>) -> R
    {
        let env_lifetime = ();
        let env = unsafe { NifEnv::new(&env_lifetime, *self.env) };
        closure(env)
    }

    /// Run a closure that produces a term, then send the term to another process.
    ///
    /// After the closure runs and the message is sent, the environment is cleared as though by
    /// calling the `.clear()` method.
    pub fn send<F>(&mut self, recipient: ErlNifPid, closure: F)
        where F: for<'a> FnOnce(NifEnv<'a>) -> NifTerm<'a>
    {
        let env_lifetime = ();
        let c_env = *self.env;
        let env = unsafe { NifEnv::new(&env_lifetime, c_env) };
        let message = closure(env);

        self.env = Arc::new(c_env);
        unsafe {
            nif_interface::enif_send(*self.env, &recipient, *self.env, message.as_c_arg());
        }
    }

    /// Free all terms in this environment and clear it for reuse.
    ///
    /// This invalidates `SavedTerm`s that were saved in this environment;
    /// if you later try to `.load()` one, you'll get a panic.
    ///
    /// Unless you call this method after a call to `run()`, all terms created within the
    /// environment hang around in memory until the `OwnedEnv` is dropped: garbage collection does
    /// not continually happen as needed in a NIF environment.
    pub fn clear(&mut self) {
        let c_env = *self.env;
        self.env = Arc::new(c_env);
        unsafe { nif_interface::enif_clear_env(c_env); }
    }

    /// Save a term for use in a later call to `.run()` or `.send()`.
    ///
    /// For your safety, Rust doesn't let you save `NifTerm` values from one `.run()` call to a
    /// later `.run()` call. If you try, it'll complain about lifetimes.
    ///
    /// `.save()` offers a way to do this. For example, maybe you'd like to copy a term from the
    /// caller into an `OwnedEnv`, then use that term on another thread.
    ///
    ///     # use rustler::{ NifEnv, NifTerm };
    ///     use rustler::env::OwnedEnv;
    ///     use std::thread;
    ///
    ///     fn thread_example<'a>(env: NifEnv<'a>, term: NifTerm<'a>) {
    ///         // Copy `term` into a new OwnedEnv, for use on another thread.
    ///         let mut thread_env = OwnedEnv::new();
    ///         let saved_term = thread_env.save(term);
    ///
    ///         thread::spawn(move || {
    ///             // Now run some code on the thread, using the saved term.
    ///             thread_env.run(|env| {
    ///                 let term = saved_term.load(env);
    ///                 //... do stuff with term ...
    ///             });
    ///         });
    ///     }
    ///
    /// **Note: There is no way to save terms across `OwnedEnv::send()` or `clear()`.**
    /// If you try, the `.load()` call will panic.
    pub fn save<'a>(&self, term: NifTerm<'a>) -> SavedTerm {
        SavedTerm {
            term: unsafe { nif_term_into_env(term.as_c_arg(), term.get_env().as_c_arg(), *self.env) },
            env_generation: Arc::downgrade(&self.env),
        }
    }
}

impl Drop for OwnedEnv {
    fn drop(&mut self) {
        unsafe { nif_interface::enif_free_env(*self.env); }
    }
}

/// A term that was created in an `OwnedEnv` and saved for later use.
///
/// These are created by calling `OwnedEnv::save()`. See that method's documentation for an
/// example.
#[derive(Clone)]
pub struct SavedTerm {
    env_generation: Weak<NIF_ENV>,
    term: NIF_TERM,
}

unsafe impl Send for SavedTerm {}

impl SavedTerm {
    /// Load this saved term back into its environment.
    ///
    /// # Panics
    ///
    /// `env` must be the `NifEnv` of a `.run()` or `.send()` call on the
    /// `OwnedEnv` where this term was saved, and the `OwnedEnv` must not have
    /// been cleared or dropped since then. Otherwise this method will panic.
    pub fn load<'a>(&self, env: NifEnv<'a>) -> NifTerm<'a> {
        // Check that the saved term is still valid.
        match self.env_generation.upgrade() {
            None =>
                panic!("term is from a cleared or dropped OwnedEnv"),
            Some(ref env_arc) if **env_arc == env.as_c_arg() =>
                unsafe { NifTerm::new(env, self.term) },
            _ =>
                panic!("can't load SavedTerm into a different environment"),
        }
    }
}
<commit_msg>Get rid of redundant helper function.<commit_after>use ::{ NifEnv, NifTerm };
use wrapper::nif_interface::{ self, NIF_ENV, NIF_TERM };
pub use wrapper::nif_interface::ErlNifPid;
use std::mem;
use std::sync::{Arc, Weak};

impl<'a> NifEnv<'a> {
    /// Return the calling process's pid.
    ///
    /// # Panics
    ///
    /// Panics if this environment is process-independent.  (The only way to get such an
    /// environment is to use `OwnedEnv`.  The `NifEnv` that Rustler passes to NIFs when they're
    /// called is always associated with the calling Erlang process.)
    pub fn pid(self) -> ErlNifPid {
        let mut pid: ErlNifPid = unsafe { mem::uninitialized() };
        if unsafe { nif_interface::enif_self(self.as_c_arg(), &mut pid) }.is_null() {
            panic!("environment is process-independent");
        }
        pid
    }
}

/// A process-independent environment.
///
/// An owned environment is a place where Erlang terms can be created outside of a NIF call. Rust
/// code can use an owned environment to build a message and send it to an Erlang process.
///
///     use rustler::env::{OwnedEnv, ErlNifPid};
///     use rustler::NifEncoder;
///
///     fn send_string_to_pid(data: &str, pid: ErlNifPid) {
///         let mut msg_env = OwnedEnv::new();
///         msg_env.send(pid, |env| data.encode(env));
///     }
///
/// There's no way to run Erlang code in an owned environment. It's not a process. It's just a
/// workspace for building terms.
pub struct OwnedEnv {
    env: Arc<NIF_ENV>
}

unsafe impl Send for OwnedEnv {}

impl OwnedEnv {
    /// Allocates a new process-independent environment.
    pub fn new() -> OwnedEnv {
        OwnedEnv {
            env: Arc::new(unsafe { nif_interface::enif_alloc_env() })
        }
    }

    /// Run some code in this environment.
    pub fn run<F, R>(&self, closure: F) -> R
        where F: for<'a> FnOnce(NifEnv<'a>) -> R
    {
        let env_lifetime = ();
        let env = unsafe { NifEnv::new(&env_lifetime, *self.env) };
        closure(env)
    }

    /// Run a closure that produces a term, then send the term to another process.
    ///
    /// After the closure runs and the message is sent, the environment is cleared as though by
    /// calling the `.clear()` method.
    pub fn send<F>(&mut self, recipient: ErlNifPid, closure: F)
        where F: for<'a> FnOnce(NifEnv<'a>) -> NifTerm<'a>
    {
        let env_lifetime = ();
        let c_env = *self.env;
        let env = unsafe { NifEnv::new(&env_lifetime, c_env) };
        let message = closure(env);

        self.env = Arc::new(c_env);
        unsafe {
            nif_interface::enif_send(*self.env, &recipient, *self.env, message.as_c_arg());
        }
    }

    /// Free all terms in this environment and clear it for reuse.
    ///
    /// This invalidates `SavedTerm`s that were saved in this environment;
    /// if you later try to `.load()` one, you'll get a panic.
    ///
    /// Unless you call this method after a call to `run()`, all terms created within the
    /// environment hang around in memory until the `OwnedEnv` is dropped: garbage collection does
    /// not continually happen as needed in a NIF environment.
    pub fn clear(&mut self) {
        let c_env = *self.env;
        self.env = Arc::new(c_env);
        unsafe { nif_interface::enif_clear_env(c_env); }
    }

    /// Save a term for use in a later call to `.run()` or `.send()`.
    ///
    /// For your safety, Rust doesn't let you save `NifTerm` values from one `.run()` call to a
    /// later `.run()` call. If you try, it'll complain about lifetimes.
    ///
    /// `.save()` offers a way to do this. For example, maybe you'd like to copy a term from the
    /// caller into an `OwnedEnv`, then use that term on another thread.
    ///
    ///     # use rustler::{ NifEnv, NifTerm };
    ///     use rustler::env::OwnedEnv;
    ///     use std::thread;
    ///
    ///     fn thread_example<'a>(env: NifEnv<'a>, term: NifTerm<'a>) {
    ///         // Copy `term` into a new OwnedEnv, for use on another thread.
    ///         let mut thread_env = OwnedEnv::new();
    ///         let saved_term = thread_env.save(term);
    ///
    ///         thread::spawn(move || {
    ///             // Now run some code on the thread, using the saved term.
    ///             thread_env.run(|env| {
    ///                 let term = saved_term.load(env);
    ///                 //... do stuff with term ...
    ///             });
    ///         });
    ///     }
    ///
    /// **Note: There is no way to save terms across `OwnedEnv::send()` or `clear()`.**
    /// If you try, the `.load()` call will panic.
    pub fn save<'a>(&self, term: NifTerm<'a>) -> SavedTerm {
        SavedTerm {
            term: self.run(|env| term.in_env(env).as_c_arg()),
            env_generation: Arc::downgrade(&self.env),
        }
    }
}

impl Drop for OwnedEnv {
    fn drop(&mut self) {
        unsafe { nif_interface::enif_free_env(*self.env); }
    }
}

/// A term that was created in an `OwnedEnv` and saved for later use.
///
/// These are created by calling `OwnedEnv::save()`. See that method's documentation for an
/// example.
#[derive(Clone)]
pub struct SavedTerm {
    env_generation: Weak<NIF_ENV>,
    term: NIF_TERM,
}

unsafe impl Send for SavedTerm {}

impl SavedTerm {
    /// Load this saved term back into its environment.
    ///
    /// # Panics
    ///
    /// `env` must be the `NifEnv` of a `.run()` or `.send()` call on the
    /// `OwnedEnv` where this term was saved, and the `OwnedEnv` must not have
    /// been cleared or dropped since then. Otherwise this method will panic.
    pub fn load<'a>(&self, env: NifEnv<'a>) -> NifTerm<'a> {
        // Check that the saved term is still valid.
        match self.env_generation.upgrade() {
            None =>
                panic!("term is from a cleared or dropped OwnedEnv"),
            Some(ref env_arc) if **env_arc == env.as_c_arg() =>
                unsafe { NifTerm::new(env, self.term) },
            _ =>
                panic!("can't load SavedTerm into a different environment"),
        }
    }
}
<|endoftext|>


<commit_before>
use gfx;
use graphics::{ Context, BackEnd };
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;

use Texture;

static VERTEX_SHADER: [&'static [u8]; 2] = [
b"#version 120
uniform vec4 color;

attribute vec2 pos;

void main() {
    gl_Position = vec4(pos, 0.0, 1.0);
}
",
b"#version 150 core
uniform vec4 color;

in vec2 pos;

void main() {
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
];

static FRAGMENT_SHADER: [&'static [u8]; 2] = [
b"#version 120
uniform vec4 color;

void main() {
    gl_FragColor = color;
}
",
b"#version 150 core
uniform vec4 color;

out vec4 o_Color;

void main() {
    o_Color = color;
}
"
];

static VERTEX_SHADER_UV: [&'static [u8]; 2] = [
b"#version 120
uniform sampler2D s_texture;
uniform vec4 color;

attribute vec2 pos;
attribute vec2 uv;

varying vec2 v_UV;

void main() {
    v_UV = uv;
    gl_Position = vec4(pos, 0.0, 1.0);
}
",
b"#version 150 core
uniform sampler2D s_texture;
uniform vec4 color;

in vec2 pos;
in vec2 uv;
out vec2 v_UV;
void main() {
    v_UV = uv;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
];

static FRAGMENT_SHADER_UV: [&'static [u8]; 2] = [
b"#version 120
uniform sampler2D s_texture;
uniform vec4 color;

varying vec2 v_UV;

void main()
{
    gl_FragColor = texture2D(s_texture, v_UV) * color;
}
",
b"#version 150 core
uniform sampler2D s_texture;
uniform vec4 color;

out vec4 o_Color;

in vec2 v_UV;

void main()
{
    o_Color = texture(s_texture, v_UV) * color;
}
"
];

static POS_COMPONENTS: usize = 2;
static UV_COMPONENTS: usize = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

#[vertex_format]
struct PositionFormat { pos: [f32; 2] }

#[vertex_format]
struct ColorFormat { color: [f32; 4] }

#[vertex_format]
struct TexCoordsFormat { uv: [f32; 2] }

#[shader_param]
struct Params {
    color: [f32; 4],
}

#[shader_param]
struct ParamsUV {
    color: [f32; 4],
    s_texture: gfx::shade::TextureParam,
}

/// The graphics back-end.
pub struct G2D {
    buffer_pos: gfx::BufferHandle<gfx::GlResources, f32>,
    buffer_uv: gfx::BufferHandle<gfx::GlResources, f32>,
    batch: gfx::batch::OwnedBatch<Params>,
    batch_uv: gfx::batch::OwnedBatch<ParamsUV>,
}

impl G2D {
    /// Creates a new G2D object.
    pub fn new<D: gfx::Device>(device: &mut D) -> G2D {
        use gfx::DeviceExt;

        let shader_model = device.get_capabilities().shader_model;

        let vertex = gfx::ShaderSource {
            glsl_120: Some(VERTEX_SHADER[0]),
            glsl_150: Some(VERTEX_SHADER[1]),
            .. gfx::ShaderSource::empty()
        };
        let fragment = gfx::ShaderSource {
            glsl_120: Some(FRAGMENT_SHADER[0]),
            glsl_150: Some(FRAGMENT_SHADER[1]),
            .. gfx::ShaderSource::empty()
        };

        let program = device.link_program(
            vertex.choose(shader_model).unwrap(),
            fragment.choose(shader_model).unwrap())
            .unwrap();

        let vertex = gfx::ShaderSource {
            glsl_120: Some(VERTEX_SHADER_UV[0]),
            glsl_150: Some(VERTEX_SHADER_UV[1]),
            .. gfx::ShaderSource::empty()
        };
        let fragment = gfx::ShaderSource {
            glsl_120: Some(FRAGMENT_SHADER_UV[0]),
            glsl_150: Some(FRAGMENT_SHADER_UV[1]),
            .. gfx::ShaderSource::empty()
        };

        let program_uv = device.link_program(
            vertex.choose(shader_model).unwrap(),
            fragment.choose(shader_model).unwrap())
            .unwrap();

        let buffer_pos = device.create_buffer(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::BufferUsage::Dynamic);
        let buffer_uv = device.create_buffer(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::BufferUsage::Dynamic);

        let mut mesh = gfx::Mesh::new(BUFFER_SIZE as u32);
        mesh.attributes.extend(gfx::VertexFormat::generate(
            None::<PositionFormat>,
            buffer_pos.raw()
        ).into_iter());

        // Reuse parameters from `mesh`.
        let mut mesh_uv = mesh.clone();
        mesh_uv.attributes.extend(gfx::VertexFormat::generate(
            None::<TexCoordsFormat>,
            buffer_uv.raw()
        ).into_iter());

        let params = Params {
            color: [1.0; 4],
        };
        let mut batch = gfx::batch::OwnedBatch::new(mesh, program, params)
            .unwrap();

        let sampler = device.create_sampler(
            gfx::tex::SamplerInfo::new(
                gfx::tex::FilterMethod::Trilinear,
                gfx::tex::WrapMode::Clamp)
        );

        // Create a dummy texture
        let texture_info = gfx::tex::TextureInfo {
            width: 1,
            height: 1,
            depth: 1,
            levels: 1,
            kind: gfx::tex::TextureKind::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info)
            .unwrap();
        device.update_texture(&texture, &image_info,
                &[0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
            .unwrap();
        let params_uv = ParamsUV {
            color: [1.0; 4],
            s_texture: (texture, Some(sampler))
        };
        let mut batch_uv = gfx::batch::OwnedBatch::new(
            mesh_uv, program_uv, params_uv)
            .unwrap();

        // Disable culling.
        batch.state.primitive.method =
            gfx::state::RasterMethod::Fill(gfx::state::CullMode::Nothing);
        batch_uv.state.primitive.method =
            gfx::state::RasterMethod::Fill(gfx::state::CullMode::Nothing);

        G2D {
            buffer_pos: buffer_pos,
            buffer_uv: buffer_uv,
            batch: batch,
            batch_uv: batch_uv,
        }
    }

    /// Renders graphics to a Gfx renderer.
    pub fn draw<C, F>(
        &mut self,
        renderer: &mut gfx::Renderer<C>,
        frame: &gfx::Frame,
        mut f: F
    )
        where
            C: gfx::Device,
            F: FnMut(Context, &mut GraphicsBackEnd<C>)
    {
        let ref mut g = GraphicsBackEnd::new(
            renderer,
            frame,
            self
        );
        let c = Context::abs(
            frame.width as f64,
            frame.height as f64
        );
        g.enable_alpha_blend();
        f(c, g);
        g.disable_alpha_blend();
    }
}

/// Used for rendering 2D graphics.
pub struct GraphicsBackEnd<'a, C: 'a + gfx::Device> {
    renderer: &'a mut gfx::Renderer<C>,
    frame: &'a gfx::Frame,
    g2d: &'a mut G2D,
}

impl<'a, C: gfx::Device> GraphicsBackEnd<'a, C> {
    /// Creates a new object for rendering 2D graphics.
    pub fn new(renderer: &'a mut gfx::Renderer<C>,
               frame: &'a gfx::Frame,
               g2d: &'a mut G2D) -> GraphicsBackEnd<'a, C> {
        GraphicsBackEnd {
            renderer: renderer,
            frame: frame,
            g2d: g2d,
        }
    }

    /// Returns true if texture has alpha channel.
    pub fn has_texture_alpha(&self, texture: &Texture) -> bool {
        use gfx::tex::Components::RGBA;

        texture.handle.get_info().format.get_components() == Some(RGBA)
    }

    /// Enabled alpha blending.
    pub fn enable_alpha_blend(&mut self) {
        use std::default::Default;
        use gfx::state::InverseFlag::{Normal, Inverse};
        use gfx::state::Factor;
        use gfx::state::BlendValue::SourceAlpha;

        let blend = gfx::state::Blend {
            value: [1.0, 1.0, 1.0, 1.0],
            color: gfx::state::BlendChannel {
                    equation: gfx::state::Equation::Add,
                    source: Factor(Normal, SourceAlpha),
                    destination: Factor(Inverse, SourceAlpha)
                },
            alpha: Default::default()
        };

        self.g2d.batch.state.blend = Some(blend);
        self.g2d.batch_uv.state.blend = Some(blend);
    }

    /// Disables alpha blending.
    pub fn disable_alpha_blend(&mut self) {
        self.g2d.batch.state.blend = None;
        self.g2d.batch_uv.state.blend = None;
    }
}

impl<'a, C: gfx::Device> BackEnd
for GraphicsBackEnd<'a, C> {
    type Texture = Texture;

    fn clear(&mut self, color: [f32; 4]) {
        let &mut GraphicsBackEnd {
            ref mut renderer,
            frame,
            ..
        } = self;
        renderer.clear(
                gfx::ClearData {
                    color: color,
                    depth: 0.0,
                    stencil: 0,
                },
                gfx::COLOR,
                frame
            );
    }

    fn tri_list<F>(&mut self, color: &[f32; 4], mut f: F)
        where F: FnMut(&mut FnMut(&[f32]))
    {
        let &mut GraphicsBackEnd {
            ref mut renderer,
            ref frame,
            g2d: &mut G2D {
                ref mut buffer_pos,
                ref mut batch,
                ..
            },
        } = self;

        batch.param.color = *color;

        f(&mut |vertices: &[f32]| {
            renderer.update_buffer_vec(*buffer_pos, vertices, 0);

            let n = vertices.len() / POS_COMPONENTS;
            batch.slice = gfx::Slice {
                    prim_type: gfx::PrimitiveType::TriangleList,
                    start: 0,
                    end: n as u32,
                    kind: gfx::SliceKind::Vertex
                };
            let _ = renderer.draw(batch, *frame);
        })
    }

    fn tri_list_uv<F>(&mut self, color: &[f32; 4], texture: &Texture, mut f: F)
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        let &mut GraphicsBackEnd {
            ref mut renderer,
            ref frame,
            g2d: &mut G2D {
                ref mut buffer_pos,
                ref mut buffer_uv,
                ref mut batch_uv,
                ..
            },
        } = self;

        batch_uv.param.s_texture.0 = texture.handle;
        batch_uv.param.color = *color;

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            assert_eq!(
                vertices.len() * UV_COMPONENTS,
                texture_coords.len() * POS_COMPONENTS
            );
            renderer.update_buffer_vec(*buffer_pos, vertices, 0);
            renderer.update_buffer_vec(*buffer_uv, texture_coords, 0);

            let n = vertices.len() / POS_COMPONENTS;
            batch_uv.slice = gfx::Slice {
                    prim_type: gfx::PrimitiveType::TriangleList,
                    start: 0,
                    end: n as u32,
                    kind: gfx::SliceKind::Vertex
                };
            let _ = renderer.draw(batch_uv, *frame);
        })
    }
}
<commit_msg>Workaround for buffer handle copy bug<commit_after>
use gfx;
use graphics::{ Context, BackEnd };
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;

use Texture;

static VERTEX_SHADER: [&'static [u8]; 2] = [
b"#version 120
uniform vec4 color;

attribute vec2 pos;

void main() {
    gl_Position = vec4(pos, 0.0, 1.0);
}
",
b"#version 150 core
uniform vec4 color;

in vec2 pos;

void main() {
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
];

static FRAGMENT_SHADER: [&'static [u8]; 2] = [
b"#version 120
uniform vec4 color;

void main() {
    gl_FragColor = color;
}
",
b"#version 150 core
uniform vec4 color;

out vec4 o_Color;

void main() {
    o_Color = color;
}
"
];

static VERTEX_SHADER_UV: [&'static [u8]; 2] = [
b"#version 120
uniform sampler2D s_texture;
uniform vec4 color;

attribute vec2 pos;
attribute vec2 uv;

varying vec2 v_UV;

void main() {
    v_UV = uv;
    gl_Position = vec4(pos, 0.0, 1.0);
}
",
b"#version 150 core
uniform sampler2D s_texture;
uniform vec4 color;

in vec2 pos;
in vec2 uv;
out vec2 v_UV;
void main() {
    v_UV = uv;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
];

static FRAGMENT_SHADER_UV: [&'static [u8]; 2] = [
b"#version 120
uniform sampler2D s_texture;
uniform vec4 color;

varying vec2 v_UV;

void main()
{
    gl_FragColor = texture2D(s_texture, v_UV) * color;
}
",
b"#version 150 core
uniform sampler2D s_texture;
uniform vec4 color;

out vec4 o_Color;

in vec2 v_UV;

void main()
{
    o_Color = texture(s_texture, v_UV) * color;
}
"
];

static POS_COMPONENTS: usize = 2;
static UV_COMPONENTS: usize = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

#[vertex_format]
struct PositionFormat { pos: [f32; 2] }

#[vertex_format]
struct ColorFormat { color: [f32; 4] }

#[vertex_format]
struct TexCoordsFormat { uv: [f32; 2] }

#[shader_param]
struct Params {
    color: [f32; 4],
}

#[shader_param]
struct ParamsUV {
    color: [f32; 4],
    s_texture: gfx::shade::TextureParam,
}

/// The graphics back-end.
pub struct G2D {
    buffer_pos: gfx::BufferHandle<gfx::GlResources, f32>,
    buffer_uv: gfx::BufferHandle<gfx::GlResources, f32>,
    batch: gfx::batch::OwnedBatch<Params>,
    batch_uv: gfx::batch::OwnedBatch<ParamsUV>,
}

impl G2D {
    /// Creates a new G2D object.
    pub fn new<D: gfx::Device>(device: &mut D) -> G2D {
        use gfx::DeviceExt;

        let shader_model = device.get_capabilities().shader_model;

        let vertex = gfx::ShaderSource {
            glsl_120: Some(VERTEX_SHADER[0]),
            glsl_150: Some(VERTEX_SHADER[1]),
            .. gfx::ShaderSource::empty()
        };
        let fragment = gfx::ShaderSource {
            glsl_120: Some(FRAGMENT_SHADER[0]),
            glsl_150: Some(FRAGMENT_SHADER[1]),
            .. gfx::ShaderSource::empty()
        };

        let program = device.link_program(
            vertex.choose(shader_model).unwrap(),
            fragment.choose(shader_model).unwrap())
            .unwrap();

        let vertex = gfx::ShaderSource {
            glsl_120: Some(VERTEX_SHADER_UV[0]),
            glsl_150: Some(VERTEX_SHADER_UV[1]),
            .. gfx::ShaderSource::empty()
        };
        let fragment = gfx::ShaderSource {
            glsl_120: Some(FRAGMENT_SHADER_UV[0]),
            glsl_150: Some(FRAGMENT_SHADER_UV[1]),
            .. gfx::ShaderSource::empty()
        };

        let program_uv = device.link_program(
            vertex.choose(shader_model).unwrap(),
            fragment.choose(shader_model).unwrap())
            .unwrap();

        let buffer_pos = device.create_buffer(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::BufferUsage::Dynamic);
        let buffer_uv = device.create_buffer(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::BufferUsage::Dynamic);

        let mut mesh = gfx::Mesh::new(BUFFER_SIZE as u32);
        mesh.attributes.extend(gfx::VertexFormat::generate(
            None::<PositionFormat>,
            buffer_pos.raw()
        ).into_iter());

        // Reuse parameters from `mesh`.
        let mut mesh_uv = mesh.clone();
        mesh_uv.attributes.extend(gfx::VertexFormat::generate(
            None::<TexCoordsFormat>,
            buffer_uv.raw()
        ).into_iter());

        let params = Params {
            color: [1.0; 4],
        };
        let mut batch = gfx::batch::OwnedBatch::new(mesh, program, params)
            .unwrap();

        let sampler = device.create_sampler(
            gfx::tex::SamplerInfo::new(
                gfx::tex::FilterMethod::Trilinear,
                gfx::tex::WrapMode::Clamp)
        );

        // Create a dummy texture
        let texture_info = gfx::tex::TextureInfo {
            width: 1,
            height: 1,
            depth: 1,
            levels: 1,
            kind: gfx::tex::TextureKind::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info)
            .unwrap();
        device.update_texture(&texture, &image_info,
                &[0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
            .unwrap();
        let params_uv = ParamsUV {
            color: [1.0; 4],
            s_texture: (texture, Some(sampler))
        };
        let mut batch_uv = gfx::batch::OwnedBatch::new(
            mesh_uv, program_uv, params_uv)
            .unwrap();

        // Disable culling.
        batch.state.primitive.method =
            gfx::state::RasterMethod::Fill(gfx::state::CullMode::Nothing);
        batch_uv.state.primitive.method =
            gfx::state::RasterMethod::Fill(gfx::state::CullMode::Nothing);

        G2D {
            buffer_pos: buffer_pos,
            buffer_uv: buffer_uv,
            batch: batch,
            batch_uv: batch_uv,
        }
    }

    /// Renders graphics to a Gfx renderer.
    pub fn draw<C, F>(
        &mut self,
        renderer: &mut gfx::Renderer<C>,
        frame: &gfx::Frame,
        mut f: F
    )
        where
            C: gfx::Device,
            F: FnMut(Context, &mut GraphicsBackEnd<C>)
    {
        let ref mut g = GraphicsBackEnd::new(
            renderer,
            frame,
            self
        );
        let c = Context::abs(
            frame.width as f64,
            frame.height as f64
        );
        g.enable_alpha_blend();
        f(c, g);
        g.disable_alpha_blend();
    }
}

/// Used for rendering 2D graphics.
pub struct GraphicsBackEnd<'a, C: 'a + gfx::Device> {
    renderer: &'a mut gfx::Renderer<C>,
    frame: &'a gfx::Frame,
    g2d: &'a mut G2D,
}

impl<'a, C: gfx::Device> GraphicsBackEnd<'a, C> {
    /// Creates a new object for rendering 2D graphics.
    pub fn new(renderer: &'a mut gfx::Renderer<C>,
               frame: &'a gfx::Frame,
               g2d: &'a mut G2D) -> GraphicsBackEnd<'a, C> {
        GraphicsBackEnd {
            renderer: renderer,
            frame: frame,
            g2d: g2d,
        }
    }

    /// Returns true if texture has alpha channel.
    pub fn has_texture_alpha(&self, texture: &Texture) -> bool {
        use gfx::tex::Components::RGBA;

        texture.handle.get_info().format.get_components() == Some(RGBA)
    }

    /// Enabled alpha blending.
    pub fn enable_alpha_blend(&mut self) {
        use std::default::Default;
        use gfx::state::InverseFlag::{Normal, Inverse};
        use gfx::state::Factor;
        use gfx::state::BlendValue::SourceAlpha;

        let blend = gfx::state::Blend {
            value: [1.0, 1.0, 1.0, 1.0],
            color: gfx::state::BlendChannel {
                    equation: gfx::state::Equation::Add,
                    source: Factor(Normal, SourceAlpha),
                    destination: Factor(Inverse, SourceAlpha)
                },
            alpha: Default::default()
        };

        self.g2d.batch.state.blend = Some(blend);
        self.g2d.batch_uv.state.blend = Some(blend);
    }

    /// Disables alpha blending.
    pub fn disable_alpha_blend(&mut self) {
        self.g2d.batch.state.blend = None;
        self.g2d.batch_uv.state.blend = None;
    }
}

impl<'a, C: gfx::Device> BackEnd
for GraphicsBackEnd<'a, C> {
    type Texture = Texture;

    fn clear(&mut self, color: [f32; 4]) {
        let &mut GraphicsBackEnd {
            ref mut renderer,
            frame,
            ..
        } = self;
        renderer.clear(
                gfx::ClearData {
                    color: color,
                    depth: 0.0,
                    stencil: 0,
                },
                gfx::COLOR,
                frame
            );
    }

    fn tri_list<F>(&mut self, color: &[f32; 4], mut f: F)
        where F: FnMut(&mut FnMut(&[f32]))
    {
        let &mut GraphicsBackEnd {
            ref mut renderer,
            ref frame,
            g2d: &mut G2D {
                ref mut buffer_pos,
                ref mut batch,
                ..
            },
        } = self;

        batch.param.color = *color;

        f(&mut |vertices: &[f32]| {
            renderer.update_buffer_vec(buffer_pos.clone(), vertices, 0);

            let n = vertices.len() / POS_COMPONENTS;
            batch.slice = gfx::Slice {
                    prim_type: gfx::PrimitiveType::TriangleList,
                    start: 0,
                    end: n as u32,
                    kind: gfx::SliceKind::Vertex
                };
            let _ = renderer.draw(batch, *frame);
        })
    }

    fn tri_list_uv<F>(&mut self, color: &[f32; 4], texture: &Texture, mut f: F)
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        let &mut GraphicsBackEnd {
            ref mut renderer,
            ref frame,
            g2d: &mut G2D {
                ref mut buffer_pos,
                ref mut buffer_uv,
                ref mut batch_uv,
                ..
            },
        } = self;

        batch_uv.param.s_texture.0 = texture.handle;
        batch_uv.param.color = *color;

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            assert_eq!(
                vertices.len() * UV_COMPONENTS,
                texture_coords.len() * POS_COMPONENTS
            );
            renderer.update_buffer_vec(buffer_pos.clone(), vertices, 0);
            renderer.update_buffer_vec(buffer_uv.clone(), texture_coords, 0);

            let n = vertices.len() / POS_COMPONENTS;
            batch_uv.slice = gfx::Slice {
                    prim_type: gfx::PrimitiveType::TriangleList,
                    start: 0,
                    end: n as u32,
                    kind: gfx::SliceKind::Vertex
                };
            let _ = renderer.draw(batch_uv, *frame);
        })
    }
}
<|endoftext|>


<commit_before>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 }
        $( else if $m1 { $h1 } )*
    }}
}

pub fn get(request: Request, mut response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request, response),
            path == "/ip" => origin(&request, response),
            path.starts_with("/status") => status(&request, response),
            path.starts_with("/test") => test(&request, response),
        ];
    }
}

fn index(request: &Request, mut response: Response) {
    let index = "<!DOCTYPE html>

            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(index.len() as u64));
    response.start().unwrap().write(index.as_bytes()).unwrap();
}

fn status(request: &Request, mut response: Response) {
    *response.status_mut() = StatusCode::ImATeapot;
}

fn origin(request: &Request, mut response: Response) {
    let text = "Remote address decoding is not implemented yet";
    response.headers_mut().set(ContentType::plaintext());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}

fn test(request: &Request, mut response: Response) {
    let text = format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
                       request.remote_addr,
                       request.method,
                       request.version,
                       request.headers,
                       request.uri);
    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}
<commit_msg>macro reformat<commit_after>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 } $( else if $m1 { $h1 } )*
    }}
}

pub fn get(request: Request, mut response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request, response),
            path == "/ip" => origin(&request, response),
            path.starts_with("/status") => status(&request, response),
            path.starts_with("/test") => test(&request, response),
        ];
    }
}

fn index(request: &Request, mut response: Response) {
    let index = "<!DOCTYPE html>

            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(index.len() as u64));
    response.start().unwrap().write(index.as_bytes()).unwrap();
}

fn status(request: &Request, mut response: Response) {
    *response.status_mut() = StatusCode::ImATeapot;
}

fn origin(request: &Request, mut response: Response) {
    let text = "Remote address decoding is not implemented yet";
    response.headers_mut().set(ContentType::plaintext());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}

fn test(request: &Request, mut response: Response) {
    let text = format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
                       request.remote_addr,
                       request.method,
                       request.version,
                       request.headers,
                       request.uri);
    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}
<|endoftext|>