<commit_before>use std::ops::Deref;
use std::cell::UnsafeCell;
use std::rc::Rc;
use std::mem;
use std::fmt;

use self::Inner::{Evaluated, EvaluationInProgress, Unevaluated, Redirect};

/// Helper macro for writing lazy expressions
///
/// ```rust
/// #[macro_use] extern crate immutable_seq;
/// # use immutable_seq::lazy::value;
/// # fn main() {
/// let thunk = lazy!{
///     println!("Evaluated!");
///     value(7u32)
/// };
/// assert_eq!(*thunk, 7u32);
/// # }
/// ```
#[macro_export]
macro_rules! lazy {
    ($($e: stmt);*) => {
        $crate::lazy::Thunk::new(move || { $($e);* })
    }
}

#[macro_export]
macro_rules! lazy_val {
    ($($e: stmt);*) => {
        $crate::lazy::Thunk::new(move || { value({$($e);*}) })
    }
}

#[macro_export]
macro_rules! lazy_redirect {
    ($($e: stmt);*) => {
        $crate::lazy::Thunk::new(move || { redirect({$($e);*}) })
    }
}

pub fn strict<T>(v: T) -> Thunk<T> {
    Thunk::evaluated(v)
}

pub fn redirect<T>(t: Thunk<T>) -> ThunkResult<T> {
    ThunkResult::Redirect(t)
}

pub fn value<T>(v: T) -> ThunkResult<T> {
    ThunkResult::Value(v)
}

/// A sometimes-cleaner name for a lazily evaluated value.
pub type Lazy<T> = Thunk<T>;

/// A lazily evaluated value.
pub struct Thunk<T> (UnsafeCell<Rc<UnsafeCell<Inner<T>>>>);

impl<T> Thunk<T> {
    /// Create a lazily evaluated value from a proc that returns that value.
    ///
    /// You can construct Thunk's manually using this, but the lazy! macro
    /// is preferred.
    ///
    /// ```rust
    /// # use immutable_seq::lazy::{Thunk, value};
    /// let expensive = Thunk::new(|| { println!("Evaluated!"); value(7u32) });
    /// assert_eq!(*expensive, 7u32); // "Evaluated!" gets printed here.
    /// assert_eq!(*expensive, 7u32); // Nothing printed.
    /// ```
    pub fn new<F>(producer: F) -> Thunk<T>
    where F: FnOnce() -> ThunkResult<T> + 'static {
        Thunk(UnsafeCell::new(Rc::new(UnsafeCell::new(Unevaluated(Producer::new(producer))))))
    }

    /// Create a new, evaluated, thunk from a value.
    pub fn evaluated(val: T) -> Thunk<T> {
        Thunk(UnsafeCell::new(Rc::new(UnsafeCell::new(Evaluated(val)))))
    }

    /// Force evaluation of a thunk.
    pub fn force(&self) {
        loop {
            match *self.inner() {
                Evaluated(_) => return,
                EvaluationInProgress => {
                    panic!("Thunk::force called recursively. (A Thunk tried to force itself while trying to force itself).")
                },
                Redirect(ref t) => {
                    self.redirect(t.clone());
                    continue;
                },
                Unevaluated(_) => ()
            };
            break;
        }

        match mem::replace(self.inner(), EvaluationInProgress) {
            Unevaluated(producer) => {
                *self.inner() = EvaluationInProgress;
                match producer.invoke() {
                    ThunkResult::Value(x) =>
                        *self.inner() = Evaluated(x),
                    ThunkResult::Redirect(t) => {
                        t.force();
                        *self.inner() = Redirect(t.clone());
                        self.redirect(t);
                    }
                }
            }
            _ => {
                let x = 42;
                println!("thats not good {}",x);
                // unsafe { debug_unreachable!() }
            }
        }
    }

    fn inner(&self) -> &mut Inner<T> {
        match *self {
            Thunk(ref cell) => unsafe {
                &mut *(**cell.get()).get()
            }
        }
    }

    fn rc(&self) -> &mut Rc<UnsafeCell<Inner<T>>> {
        match *self {
            Thunk(ref cell) => unsafe {
                &mut *cell.get()
            }
        }
    }

    fn redirect(&self, t: Thunk<T>) {
        *self.rc() = t.rc().clone();
    }
}

impl<T> Deref for Thunk<T> {
    type Target = T;

    fn deref(&self) -> &T {
        self.force();
        match *self.inner()  {
            Evaluated(ref val) => val,
            _ => unreachable!(),
        }
    }
}

impl<T> Clone for Thunk<T> {
    fn clone(&self) -> Thunk<T> {
        Thunk(UnsafeCell::new(self.rc().clone()))
    }
}

impl<T> fmt::Debug for Thunk<T>
    where T: fmt::Debug
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("Thunk")
            .field(self.inner())
            .finish()
    }
}

/// Represents the two possible things a `Thunk<T>` can return: either a `T` value, or another `Thunk<T>`.
#[derive(Debug)]
pub enum ThunkResult<T> {
    Value(T),
    Redirect(Thunk<T>)
}

struct Producer<T> {
    inner: Box<Invoke<T>>
}

impl<T> fmt::Debug for Producer<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Producer{{...}}")
    }
}

impl<T> Producer<T> {
    fn new<F: FnOnce() -> T + 'static>(f: F) -> Producer<T> {
        Producer {
            inner: Box::new(move || {
                f()
            }) as Box<Invoke<T>>
        }
    }

    fn invoke(self) -> T {
        self.inner.invoke()
    }
}

#[derive(Debug)]
enum Inner<T> {
    Evaluated(T),
    EvaluationInProgress,
    Unevaluated(Producer<ThunkResult<T>>),
    Redirect(Thunk<T>),
}

#[doc(hidden)]
pub trait Invoke<T> {
    fn invoke(self: Box<Self>) -> T;
}

impl<T, F> Invoke<T> for F
    where F: FnOnce() -> T
{
    fn invoke(self: Box<F>) -> T {
        let f = *self;
        f()
    }
}
<commit_msg>Added attribution comment to lazy code<commit_after>// This code is based on code from Jonathan Reem's rust-lazy library (https://github.com/reem/rust-lazy)

use std::ops::Deref;
use std::cell::UnsafeCell;
use std::rc::Rc;
use std::mem;
use std::fmt;

use self::Inner::{Evaluated, EvaluationInProgress, Unevaluated, Redirect};

/// Helper macro for writing lazy expressions
///
/// ```rust
/// #[macro_use] extern crate immutable_seq;
/// # use immutable_seq::lazy::value;
/// # fn main() {
/// let thunk = lazy!{
///     println!("Evaluated!");
///     value(7u32)
/// };
/// assert_eq!(*thunk, 7u32);
/// # }
/// ```
#[macro_export]
macro_rules! lazy {
    ($($e: stmt);*) => {
        $crate::lazy::Thunk::new(move || { $($e);* })
    }
}

#[macro_export]
macro_rules! lazy_val {
    ($($e: stmt);*) => {
        $crate::lazy::Thunk::new(move || { value({$($e);*}) })
    }
}

#[macro_export]
macro_rules! lazy_redirect {
    ($($e: stmt);*) => {
        $crate::lazy::Thunk::new(move || { redirect({$($e);*}) })
    }
}

pub fn strict<T>(v: T) -> Thunk<T> {
    Thunk::evaluated(v)
}

pub fn redirect<T>(t: Thunk<T>) -> ThunkResult<T> {
    ThunkResult::Redirect(t)
}

pub fn value<T>(v: T) -> ThunkResult<T> {
    ThunkResult::Value(v)
}

/// A sometimes-cleaner name for a lazily evaluated value.
pub type Lazy<T> = Thunk<T>;

/// A lazily evaluated value.
pub struct Thunk<T> (UnsafeCell<Rc<UnsafeCell<Inner<T>>>>);

impl<T> Thunk<T> {
    /// Create a lazily evaluated value from a proc that returns that value.
    ///
    /// You can construct Thunk's manually using this, but the lazy! macro
    /// is preferred.
    ///
    /// ```rust
    /// # use immutable_seq::lazy::{Thunk, value};
    /// let expensive = Thunk::new(|| { println!("Evaluated!"); value(7u32) });
    /// assert_eq!(*expensive, 7u32); // "Evaluated!" gets printed here.
    /// assert_eq!(*expensive, 7u32); // Nothing printed.
    /// ```
    pub fn new<F>(producer: F) -> Thunk<T>
    where F: FnOnce() -> ThunkResult<T> + 'static {
        Thunk(UnsafeCell::new(Rc::new(UnsafeCell::new(Unevaluated(Producer::new(producer))))))
    }

    /// Create a new, evaluated, thunk from a value.
    pub fn evaluated(val: T) -> Thunk<T> {
        Thunk(UnsafeCell::new(Rc::new(UnsafeCell::new(Evaluated(val)))))
    }

    /// Force evaluation of a thunk.
    pub fn force(&self) {
        loop {
            match *self.inner() {
                Evaluated(_) => return,
                EvaluationInProgress => {
                    panic!("Thunk::force called recursively. (A Thunk tried to force itself while trying to force itself).")
                },
                Redirect(ref t) => {
                    self.redirect(t.clone());
                    continue;
                },
                Unevaluated(_) => ()
            };
            break;
        }

        match mem::replace(self.inner(), EvaluationInProgress) {
            Unevaluated(producer) => {
                *self.inner() = EvaluationInProgress;
                match producer.invoke() {
                    ThunkResult::Value(x) =>
                        *self.inner() = Evaluated(x),
                    ThunkResult::Redirect(t) => {
                        t.force();
                        *self.inner() = Redirect(t.clone());
                        self.redirect(t);
                    }
                }
            }
            _ => {
                let x = 42;
                println!("thats not good {}",x);
                // unsafe { debug_unreachable!() }
            }
        }
    }

    fn inner(&self) -> &mut Inner<T> {
        match *self {
            Thunk(ref cell) => unsafe {
                &mut *(**cell.get()).get()
            }
        }
    }

    fn rc(&self) -> &mut Rc<UnsafeCell<Inner<T>>> {
        match *self {
            Thunk(ref cell) => unsafe {
                &mut *cell.get()
            }
        }
    }

    fn redirect(&self, t: Thunk<T>) {
        *self.rc() = t.rc().clone();
    }
}

impl<T> Deref for Thunk<T> {
    type Target = T;

    fn deref(&self) -> &T {
        self.force();
        match *self.inner()  {
            Evaluated(ref val) => val,
            _ => unreachable!(),
        }
    }
}

impl<T> Clone for Thunk<T> {
    fn clone(&self) -> Thunk<T> {
        Thunk(UnsafeCell::new(self.rc().clone()))
    }
}

impl<T> fmt::Debug for Thunk<T>
    where T: fmt::Debug
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("Thunk")
            .field(self.inner())
            .finish()
    }
}

/// Represents the two possible things a `Thunk<T>` can return: either a `T` value, or another `Thunk<T>`.
#[derive(Debug)]
pub enum ThunkResult<T> {
    Value(T),
    Redirect(Thunk<T>)
}

struct Producer<T> {
    inner: Box<Invoke<T>>
}

impl<T> fmt::Debug for Producer<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Producer{{...}}")
    }
}

impl<T> Producer<T> {
    fn new<F: FnOnce() -> T + 'static>(f: F) -> Producer<T> {
        Producer {
            inner: Box::new(move || {
                f()
            }) as Box<Invoke<T>>
        }
    }

    fn invoke(self) -> T {
        self.inner.invoke()
    }
}

#[derive(Debug)]
enum Inner<T> {
    Evaluated(T),
    EvaluationInProgress,
    Unevaluated(Producer<ThunkResult<T>>),
    Redirect(Thunk<T>),
}

#[doc(hidden)]
pub trait Invoke<T> {
    fn invoke(self: Box<Self>) -> T;
}

impl<T, F> Invoke<T> for F
    where F: FnOnce() -> T
{
    fn invoke(self: Box<F>) -> T {
        let f = *self;
        f()
    }
}
<|endoftext|>


<commit_before>// rust version of breakfast tool
// BreakFast is a toolkit for detecting chromosomal rearrangements
// based on RNA-seq data.

use std::env;
use std::mem;
use std::thread;
use std::sync::Arc;
use std::path::Path;
use std::io::prelude::*;
use std::fs;
use std::os::unix::io::AsRawFd;
use std::os::unix::io::FromRawFd;
use std::fs::File;
use std::process::{Command, Stdio};
use std::collections::HashMap;
use std::io::{BufReader, BufRead, Read, Write};
use rust_htslib::bam;
use rust_htslib::bam::Read as HTSRead;

extern crate clap;
extern crate bio;
extern crate rust_htslib;

mod cli;
mod lib;

// struct for having breakfast options
struct BfOptions {
    anchor_len :    usize,
    max_frag_len:   i32,
    min_mapq:       i32,
    orientation:    &'static str,
    all_reads:      bool,
    discard_duplicates: &'static str,
    min_reads:      &'static str,
    freq_above:     i32,
}

struct Evidence {
	chr: String,
	pos: u32,
	strand: bool,
	mchr: String,
	mpos: u32,
	mstrand: bool,
	sequence: String,
	frag_id: String,
	signature: String     // Breakpoint signature
}

fn main() {
  let defaults = BfOptions{ anchor_len : 0,
                            max_frag_len: 5000,
                            min_mapq: 15,
                            orientation:  "fr",
                            all_reads:  false,
                            discard_duplicates: "both-ends",
                            min_reads:    "0-0-0",
                            freq_above: 0};

  let mut anchor_len: usize   = defaults.anchor_len;
  let mut max_frag_len: i32 = defaults.max_frag_len;
  let mut min_mapq: i32     = defaults.min_mapq;
  let mut orientation       = String::from(defaults.orientation);
  let mut all_reads: bool   = defaults.all_reads;
  let mut discard_duplicates = String::from(defaults.discard_duplicates);
  let mut min_reads     = String::from(defaults.min_reads);
  let mut freq_above: i32 = defaults.freq_above;

  //arguments from src/cli.rs
  let matches = cli::build_cli().get_matches();
  //arguments from detect subcommand
  if let ("detect", Some(detect)) = matches.subcommand() {
      let bam_file = String::from(detect.value_of("bam_file").unwrap());
      let genome   = String::from(detect.value_of("genome").unwrap());

      if detect.is_present("anchor-len") {
          anchor_len = detect.value_of("anchor-len").unwrap().parse().unwrap();
      }

      if detect.is_present("orientation") {
          orientation = String::from(detect.value_of("orientation").unwrap());
      }
      detect_discordant_reads(bam_file, genome, anchor_len);
  }
}

// DETECT //
//======= //

// fn detect_discordant_pairs(sam_path: String, out_prefix: String, max_frag_len: i32,
// 	min_mapq: i32, orientation: String) {
//   println!("{:?}\t{:?}\t{:?}\t{:?}\t{:?}", sam_path, out_prefix, max_frag_len, min_mapq, orientation);

//   let mut N = 0;
//   let tmp = out_prefix.clone();
//   let given_path = Path::new(&tmp);
//   let mut sort_tmp_dir = Path::new("./");
//   if given_path.is_absolute()  {
//         sort_tmp_dir = given_path.parent().unwrap();
//   }

//   let extn = String::from(".discordant_pairs.tsv.gz");
//   let out  = out_prefix + &extn;
//   let mut file = File::create("test.txt").unwrap();

//   lib::mkdir(&tmp);
//   println!("Searching for discordant read pairs ...");

//   let (code, stdout, stderr) = sh!("sam discordant pairs --min-mapq={} {} {} | sort -k1,1 -T {:?}", min_mapq, sam_path, max_frag_len, sort_tmp_dir);

//   let mut prev : Vec<&str> = Vec::new();
//   for line in stdout.lines() {
//       let mut cols: Vec<&str> = line.split('\t').collect();
//       if cols.len() < 9 { continue; }

//       //let r1 = Regex::new(r"N").unwrap();
//       //let r2 = Regex::new(r"S").unwrap();

//       if r1.is_match(cols[5]) || r2.is_match(cols[5]) { continue; }
//       else if cols[0].ends_with("/1") || cols[0].ends_with("/2") {
//           let tmp : Vec<&str> = cols[0].split('/').collect();
//           cols[0] = tmp[0];
//       }
//       if prev.len() <= 0 { prev = cols.clone(); }
//       else if prev.len() > 0 && cols[0] != prev[0] { prev = cols.clone(); }

//       let flags = &cols[1].parse::<i32>().unwrap();
//       let mut chr   = String::from(cols[2]);
//       let mut mchr  = String::from(prev[2]);
//       let mut strand = '-';
//       let mut mstrand = '-';
//       let mut pos  = cols[3].parse::<i32>().unwrap();
//       let mut mpos = prev[3].parse::<i32>().unwrap();
//       let mut rlen = cols[9].clone().len() as i32;
//       let mut mrlen= prev[9].clone().len() as i32;

//       if chr.starts_with("chr") {  chr = chr; }
//       else { let prefix = String::from("chr"); chr = prefix + &chr;}

//       if mchr.starts_with("chr") {  chr = chr ;}
//       else { let prefix = String::from("chr"); mchr = prefix + &mchr;}

//       if chr.contains("chrM") || mchr.contains("chrM") { continue;}

//       if orientation == "fr" {
//         if chr > mchr || (chr == mchr && pos > mpos) {
//           mem::swap(&mut chr, &mut mchr);
//           mem::swap(&mut pos, &mut mpos);
//           mem::swap(&mut rlen, &mut mrlen);
//           mem::swap(&mut strand, &mut mstrand);
//         }
//         if mstrand == '+' { mstrand = '-';}
//         else { mstrand = '+'; }
//       }

//       else if orientation == "rf" {
//         if chr > mchr || (chr == mchr && pos > mpos) {
//           mem::swap(&mut chr, &mut mchr);
//           mem::swap(&mut pos, &mut mpos);
//           mem::swap(&mut rlen, &mut mrlen);
//           mem::swap(&mut strand, &mut mstrand);
//         }
//         if strand == '+' { strand = '-';}
//         else { strand = '+'; }
//       }

//       else if orientation == "ff" {
//         if chr > mchr || (chr == mchr && pos > mpos) {
//           mem::swap(&mut chr, &mut mchr);
//           mem::swap(&mut pos, &mut mpos);
//           mem::swap(&mut rlen, &mut mrlen);

//           if mstrand == '-' { mstrand = '+';} else { mstrand = '-'; }
//           if strand  == '-' { strand  = '+';} else { strand  = '-'; }
//           mem::swap(&mut strand, &mut mstrand);
//         }
//       } else { panic!("Unsupported read orientation detected."); }

//       if strand  == '-' { pos  +=  rlen - 1;}
//       if mstrand == '-' { mpos += mrlen - 1;}

//       let mut out = String::new();
//       out.push_str(&chr);out.push_str(&"\t");
//       out.push_str(&strand.to_string());out.push_str(&"\t");
//       out.push_str(&pos.to_string());out.push_str(&"\t");
//       out.push_str(&mchr);out.push_str(&"\t");
//       out.push_str(&mstrand.to_string());out.push_str(&"\t");
//       out.push_str(&mpos.to_string());out.push_str(&"\t-\n");
//       file.write_all(out.as_bytes());
//       N += 1;
//     }
//     let (wcode, wstdout, wstderr) = sh!("gzip -c {:?}.txt > {}", given_path, out);
//     let mut rm_tmp = tmp.to_string() + ".txt";
//     fs::remove_file(rm_tmp);
//     println!("Found {:?} discordant mate pairs.", N);
// }

fn detect_discordant_reads(sam_path: String, genome_path: String, anchor_len: usize) {

	let fastq = bio::io::fasta::Reader::from_file(format!("{}.fa", genome_path)).unwrap();
	println!("Reading reference genome into memory...");
	let mut genome = HashMap::new();
	for entry in fastq.records() {
		let chr = entry.unwrap();
		genome.insert(chr.id().unwrap().to_owned(), chr.seq().to_owned());
	}

    println!("Splitting unaligned reads into {} bp anchors and aligning against the genome...", anchor_len);

    let mut bowtie = Command::new("bowtie")
		.args(&["-f", "-p1", "-v0", "-m1", "-B1", "--suppress", "5,6,7,8", &genome_path, "-"])
        .stdin(Stdio::piped()).stdout(Stdio::piped())
        .spawn().unwrap();

	let mut bowtie_in = unsafe { File::from_raw_fd(bowtie.stdin.unwrap().as_raw_fd()) };
	let mut bowtie_out = unsafe { BufReader::new(File::from_raw_fd(bowtie.stdout.unwrap().as_raw_fd())) };

	thread::spawn(move || {
		let bam = bam::Reader::from_path(&sam_path).unwrap();
		let mut R = 0;
		for r in bam.records() {
			let read = r.unwrap();
			if read.is_unmapped() == false { continue; }
			if read.seq().len() < anchor_len * 2 { continue; }
			// TODO: Extract anchors from both ends of read and write in
			// interleaved FASTA format to the stdin of Bowtie.
	        R += 1;
	        let seq = read.seq().as_bytes();
	        //let tail = seq.len() - anchor_len;
	        write!(bowtie_in, ">{}_1\n{:?}\n", R, &seq[..anchor_len]);
	        //let fas = ">".to_string()+&R.to_string()+"_1\n"+&seq[..anchor_len]+"\n>"+&R.to_string()+"_2\n"+&seq[tail..]+"\n";
	        //bowtie_in
	        //child_in.send(fas).unwrap();
	    }
    });

    //println!("{}", child_out.recv().unwrap());
    //TODO: bowtie is not recognizing fata format
    // check the formatting
    // write and feed a tmpfile to bowtie maybe!?
    //write!(bowtie_stdin, "{:?}", child_out.recv().unwrap());

     /*let mut bowtie_out = String::new();
       match bowtie.stdout.unwrap().read_to_string(&mut bowtie_out) {
           Err(why) => panic!("bowtie not running!"),
           Ok(_) => print!("bowtie worked!"),
       }*/

    for l in bowtie_out.lines() {
    	let line = l.unwrap();
        println!("Bowtie output:");
        println!("{}", line);
    }

    // match fas.stdin.unwrap().write_all(samres.as_bytes()) {
    //     Err(why) => panic!("samtools results not reaching fasta"),
    //     Ok(_) => print!("fasta recvied input from samtools"),
    // }

    // let mut res = String::new();
    //   match fas.stdout.unwrap().read_to_string(&mut res) {
    //       Err(why) => panic!("fasta not running!"),
    //       Ok(_) => print!("fasta subcommand worked!"),
    //   }
    //   println!("{:?}", res.len());
}
<commit_msg>fasta stdin ro bowtie<commit_after>// rust version of breakfast tool
// BreakFast is a toolkit for detecting chromosomal rearrangements
// based on RNA-seq data.

use std::env;
use std::mem;
use std::thread;
use std::sync::Arc;
use std::path::Path;
use std::io::prelude::*;
use std::fs;
use std::os::unix::io::AsRawFd;
use std::os::unix::io::FromRawFd;
use std::fs::File;
use std::process::{Command, Stdio};
use std::collections::HashMap;
use std::io::{BufReader, BufRead, Read, Write};
use rust_htslib::bam;
use rust_htslib::bam::Read as HTSRead;

extern crate clap;
extern crate bio;
extern crate rust_htslib;

mod cli;
mod lib;

// struct for having breakfast options
struct BfOptions {
    anchor_len :    usize,
    max_frag_len:   i32,
    min_mapq:       i32,
    orientation:    &'static str,
    all_reads:      bool,
    discard_duplicates: &'static str,
    min_reads:      &'static str,
    freq_above:     i32,
}

struct Evidence {
	chr: String,
	pos: u32,
	strand: bool,
	mchr: String,
	mpos: u32,
	mstrand: bool,
	sequence: String,
	frag_id: String,
	signature: String     // Breakpoint signature
}

fn main() {
  let defaults = BfOptions{ anchor_len : 0,
                            max_frag_len: 5000,
                            min_mapq: 15,
                            orientation:  "fr",
                            all_reads:  false,
                            discard_duplicates: "both-ends",
                            min_reads:    "0-0-0",
                            freq_above: 0};

  let mut anchor_len: usize   = defaults.anchor_len;
  let mut max_frag_len: i32 = defaults.max_frag_len;
  let mut min_mapq: i32     = defaults.min_mapq;
  let mut orientation       = String::from(defaults.orientation);
  let mut all_reads: bool   = defaults.all_reads;
  let mut discard_duplicates = String::from(defaults.discard_duplicates);
  let mut min_reads     = String::from(defaults.min_reads);
  let mut freq_above: i32 = defaults.freq_above;

  //arguments from src/cli.rs
  let matches = cli::build_cli().get_matches();
  //arguments from detect subcommand
  if let ("detect", Some(detect)) = matches.subcommand() {
      let bam_file = String::from(detect.value_of("bam_file").unwrap());
      let genome   = String::from(detect.value_of("genome").unwrap());

      if detect.is_present("anchor-len") {
          anchor_len = detect.value_of("anchor-len").unwrap().parse().unwrap();
      }

      if detect.is_present("orientation") {
          orientation = String::from(detect.value_of("orientation").unwrap());
      }
      detect_discordant_reads(bam_file, genome, anchor_len);
  }
}

// DETECT //
//======= //

// fn detect_discordant_pairs(sam_path: String, out_prefix: String, max_frag_len: i32,
// 	min_mapq: i32, orientation: String) {
//   println!("{:?}\t{:?}\t{:?}\t{:?}\t{:?}", sam_path, out_prefix, max_frag_len, min_mapq, orientation);

//   let mut N = 0;
//   let tmp = out_prefix.clone();
//   let given_path = Path::new(&tmp);
//   let mut sort_tmp_dir = Path::new("./");
//   if given_path.is_absolute()  {
//         sort_tmp_dir = given_path.parent().unwrap();
//   }

//   let extn = String::from(".discordant_pairs.tsv.gz");
//   let out  = out_prefix + &extn;
//   let mut file = File::create("test.txt").unwrap();

//   lib::mkdir(&tmp);
//   println!("Searching for discordant read pairs ...");

//   let (code, stdout, stderr) = sh!("sam discordant pairs --min-mapq={} {} {} | sort -k1,1 -T {:?}", min_mapq, sam_path, max_frag_len, sort_tmp_dir);

//   let mut prev : Vec<&str> = Vec::new();
//   for line in stdout.lines() {
//       let mut cols: Vec<&str> = line.split('\t').collect();
//       if cols.len() < 9 { continue; }

//       //let r1 = Regex::new(r"N").unwrap();
//       //let r2 = Regex::new(r"S").unwrap();

//       if r1.is_match(cols[5]) || r2.is_match(cols[5]) { continue; }
//       else if cols[0].ends_with("/1") || cols[0].ends_with("/2") {
//           let tmp : Vec<&str> = cols[0].split('/').collect();
//           cols[0] = tmp[0];
//       }
//       if prev.len() <= 0 { prev = cols.clone(); }
//       else if prev.len() > 0 && cols[0] != prev[0] { prev = cols.clone(); }

//       let flags = &cols[1].parse::<i32>().unwrap();
//       let mut chr   = String::from(cols[2]);
//       let mut mchr  = String::from(prev[2]);
//       let mut strand = '-';
//       let mut mstrand = '-';
//       let mut pos  = cols[3].parse::<i32>().unwrap();
//       let mut mpos = prev[3].parse::<i32>().unwrap();
//       let mut rlen = cols[9].clone().len() as i32;
//       let mut mrlen= prev[9].clone().len() as i32;

//       if chr.starts_with("chr") {  chr = chr; }
//       else { let prefix = String::from("chr"); chr = prefix + &chr;}

//       if mchr.starts_with("chr") {  chr = chr ;}
//       else { let prefix = String::from("chr"); mchr = prefix + &mchr;}

//       if chr.contains("chrM") || mchr.contains("chrM") { continue;}

//       if orientation == "fr" {
//         if chr > mchr || (chr == mchr && pos > mpos) {
//           mem::swap(&mut chr, &mut mchr);
//           mem::swap(&mut pos, &mut mpos);
//           mem::swap(&mut rlen, &mut mrlen);
//           mem::swap(&mut strand, &mut mstrand);
//         }
//         if mstrand == '+' { mstrand = '-';}
//         else { mstrand = '+'; }
//       }

//       else if orientation == "rf" {
//         if chr > mchr || (chr == mchr && pos > mpos) {
//           mem::swap(&mut chr, &mut mchr);
//           mem::swap(&mut pos, &mut mpos);
//           mem::swap(&mut rlen, &mut mrlen);
//           mem::swap(&mut strand, &mut mstrand);
//         }
//         if strand == '+' { strand = '-';}
//         else { strand = '+'; }
//       }

//       else if orientation == "ff" {
//         if chr > mchr || (chr == mchr && pos > mpos) {
//           mem::swap(&mut chr, &mut mchr);
//           mem::swap(&mut pos, &mut mpos);
//           mem::swap(&mut rlen, &mut mrlen);

//           if mstrand == '-' { mstrand = '+';} else { mstrand = '-'; }
//           if strand  == '-' { strand  = '+';} else { strand  = '-'; }
//           mem::swap(&mut strand, &mut mstrand);
//         }
//       } else { panic!("Unsupported read orientation detected."); }

//       if strand  == '-' { pos  +=  rlen - 1;}
//       if mstrand == '-' { mpos += mrlen - 1;}

//       let mut out = String::new();
//       out.push_str(&chr);out.push_str(&"\t");
//       out.push_str(&strand.to_string());out.push_str(&"\t");
//       out.push_str(&pos.to_string());out.push_str(&"\t");
//       out.push_str(&mchr);out.push_str(&"\t");
//       out.push_str(&mstrand.to_string());out.push_str(&"\t");
//       out.push_str(&mpos.to_string());out.push_str(&"\t-\n");
//       file.write_all(out.as_bytes());
//       N += 1;
//     }
//     let (wcode, wstdout, wstderr) = sh!("gzip -c {:?}.txt > {}", given_path, out);
//     let mut rm_tmp = tmp.to_string() + ".txt";
//     fs::remove_file(rm_tmp);
//     println!("Found {:?} discordant mate pairs.", N);
// }

fn detect_discordant_reads(sam_path: String, genome_path: String, anchor_len: usize) {

	let fastq = bio::io::fasta::Reader::from_file(format!("{}.fa", genome_path)).unwrap();
	println!("Reading reference genome into memory...");
	let mut genome = HashMap::new();
	for entry in fastq.records() {
		let chr = entry.unwrap();
		genome.insert(chr.id().unwrap().to_owned(), chr.seq().to_owned());
	}

    println!("Splitting unaligned reads into {} bp anchors and aligning against the genome...", anchor_len);

    let mut bowtie = Command::new("bowtie")
		.args(&["-f", "-p1", "-v0", "-m1", "-B1", "-r", "--suppress", "5,6,7,8", &genome_path, "-"])
        .stdin(Stdio::piped()).stdout(Stdio::piped())
        .spawn().unwrap();

	let mut bowtie_in = unsafe { File::from_raw_fd(bowtie.stdin.unwrap().as_raw_fd()) };
	let mut bowtie_out = unsafe { BufReader::new(File::from_raw_fd(bowtie.stdout.unwrap().as_raw_fd())) };

	thread::spawn(move || {
		let bam = bam::Reader::from_path(&sam_path).unwrap();
		let mut R = 0;
		for r in bam.records() {
			let read = r.unwrap();
			if read.is_unmapped() == false { continue; }
			if read.seq().len() < anchor_len * 2 { continue; }
			// TODO: Extract anchors from both ends of read and write in
			// interleaved FASTA format to the stdin of Bowtie.
	        R += 1;
	        let seq = String::from_utf8(read.seq().as_bytes()).unwrap();
	        //let tail = seq.len() - anchor_len;
	        write!(bowtie_in, ">{}_1\t{:?}", R, &seq[..anchor_len]);
            println!(">{:?}_1\t{:?}", R, &seq);
	    }
    });

    //println!("{}", child_out.recv().unwrap());
    //TODO: bowtie is not recognizing fata format
    // check the formatting
    // write and feed a tmpfile to bowtie maybe!?
    //write!(bowtie_stdin, "{:?}", child_out.recv().unwrap());

     let mut bowtie_results = String::new();
       match bowtie_out.read_to_string(&mut bowtie_results) {
           Err(why) => panic!("bowtie not running!"),
           Ok(_) => print!("bowtie worked!"),
       }

    println!(" There are {} lines\t", bowtie_results);

    // match fas.stdin.unwrap().write_all(samres.as_bytes()) {
    //     Err(why) => panic!("samtools results not reaching fasta"),
    //     Ok(_) => print!("fasta recvied input from samtools"),
    // }

    // let mut res = String::new();
    //   match fas.stdout.unwrap().read_to_string(&mut res) {
    //       Err(why) => panic!("fasta not running!"),
    //       Ok(_) => print!("fasta subcommand worked!"),
    //   }
    //   println!("{:?}", res.len());
}
<|endoftext|>


<commit_before>extern crate rudit;
extern crate termion;

use std::io::{Write, stdout};
use termion::raw::IntoRawMode;
use termion::event::Key;
use termion::input::TermRead;
use termion::cursor::Goto;
use rudit::gapbuffer::GapBuffer;

fn main() {
    let mut buffer = GapBuffer::new(30);
    let mut stdout = stdout().into_raw_mode().unwrap();
    let mut index = 0;
    let mut cx: u16 = 3;
    let mut cy: u16 = 1;
    // buffer.insert(0, 'a');
    // buffer.insert(1, 'b');
    // buffer.insert(2, '\n');
    // buffer.insert(3, 'c');
    // index = 3;
    // cy = 2;
    write!(stdout,
           "{}{}",
           termion::clear::All,
           termion::cursor::Goto(cx, cy))
        .unwrap();
    stdout.flush().unwrap();
    'main: loop {

        // write!(stdout, "{}", termion::clear::All).unwrap();

        draw_lines(&mut stdout, &buffer.buffer);
        draw_cursor(&mut stdout, cx, cy);
        // println!("         ");
        // println!("{}", index);
        stdout.flush().unwrap();

        for c in std::io::stdin().keys() {
            match c.unwrap() {
                Key::Char('\n') => {
                    buffer.insert(index, '\n');
                    cx = 3;
                    cy += 1;
                    index += 1;
                }
                Key::Char(c) => {
                    buffer.insert(index, c);
                    index += 1;
                    cx += 1;
                }
                Key::Up => {
                    if cy > 1 {
                        cy -= 1;
                        let prev_line = buffer.line_index_to_char_index(cy as usize - 1);
                        let prev_line_size = buffer.get_line(cy as usize - 1).len();
                        index = prev_line + std::cmp::min((cx as usize - 3), prev_line_size - 1);
                        println!("prevline {} prevline_size {}", prev_line, prev_line_size);
                    }
                }
                Key::Left => {
                    if cx > 3 {
                        cx -= 1;
                        index -= 1;
                    }
                }
                Key::Right => {
                    if buffer.buffer[index] != '\0' ||
                       buffer.buffer[buffer.buffer.len() - index + buffer.gap_start - 1] != '\0' {
                        cx += 1;
                        index += 1;
                    }
                }
                Key::Esc => break,
                _ => (),
            }
            continue 'main;
        }
        write!(stdout, "{}", termion::clear::All).unwrap();
        stdout.flush().unwrap();
        break;
    }
}

fn draw_lines(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, buffer: &Vec<char>) {
    let s: String = buffer.iter().collect();
    for (index, i) in s.split('\n').enumerate() {
        write!(stdout,
               "{}{}{}{}",
               Goto(0, (index + 1) as u16),
               index + 1,
               Goto(3, (index + 1) as u16),
               i)
            .unwrap();
    }
}

fn draw_cursor(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, cx: u16, cy: u16) {
    write!(stdout, "{}", termion::cursor::Goto(cx, cy)).unwrap();
}
<commit_msg>update<commit_after>extern crate rudit;
extern crate termion;

use std::io::{Write, stdout};
use termion::raw::IntoRawMode;
use termion::event::Key;
use termion::input::TermRead;
use termion::cursor::Goto;
use rudit::gapbuffer::GapBuffer;

fn main() {
    let mut buffer = GapBuffer::new(30);
    let mut stdout = stdout().into_raw_mode().unwrap();
    let mut index = 0;
    let mut line_num = 0;
    let mut cx: u16 = 3;
    let mut cy: u16 = 1;
    // buffer.insert(0, 'a');
    // buffer.insert(1, 'b');
    // buffer.insert(2, '\n');
    // buffer.insert(3, 'c');
    // index = 3;
    // cy = 2;
    write!(stdout,
           "{}{}",
           termion::clear::All,
           termion::cursor::Goto(cx, cy))
        .unwrap();
    stdout.flush().unwrap();
    'main: loop {

        write!(stdout, "{}", termion::clear::All).unwrap();

        draw_lines(&mut stdout, &buffer.buffer);
        draw_cursor(&mut stdout, cx, cy);
        // println!("         ");
        // println!("{}", index);
        stdout.flush().unwrap();

        for c in std::io::stdin().keys() {
            match c.unwrap() {
                Key::Char('\n') => {
                    buffer.insert(index, '\n');
                    cx = 3;
                    cy += 1;
                    index += 1;
                    line_num += 1;
                }
                Key::Char(c) => {
                    buffer.insert(index, c);
                    index += 1;
                    cx += 1;
                }
                Key::Up => {
                    if cy > 1 {
                        cy -= 1;
                        let prev_line = buffer.line_index_to_char_index(cy as usize - 1);
                        let prev_line_size = buffer.get_line(cy as usize - 1).len();
                        index = prev_line + std::cmp::min((cx as usize - 3), prev_line_size - 1);
                        if cx - 3 >= prev_line_size as u16 {
                            cx = prev_line_size as u16 + 2;
                        }
                    }
                }
                Key::Down => {
                    if cy <= line_num {
                        cy += 1;
                        let mut eol = index;
                        for i in index..buffer.len() - 1 {
                            if buffer.buffer[i] == '\n' {
                                eol += 1;
                                break;
                            }
                            eol += 1;
                        }
                        let mut size = 0;
                        for i in eol..buffer.len() {
                            if buffer.buffer[i] == '\n' {
                                break;
                            }
                            size += 1;

                        }
                        // println!("");
                        // println!("eol {} size {}", eol, size);
                       // if cx > size {
                       //     cx = size + 3;
                        //}
                        index = eol + 1;
                    }
                }
                Key::Left => {
                    if cx > 3 {
                        cx -= 1;
                        index -= 1;
                    }
                }
                Key::Right => {
                    if buffer.buffer[index] != '\0' ||
                       buffer.buffer[buffer.buffer.len() - index + buffer.gap_start - 1] != '\0' {
                        cx += 1;
                        index += 1;
                    }
                }
                Key::Esc => break,
                _ => (),
            }
            continue 'main;
        }
        write!(stdout, "{}", termion::clear::All).unwrap();
        stdout.flush().unwrap();
        break;
    }
}

fn draw_lines(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, buffer: &Vec<char>) {
    let s: String = buffer.iter().collect();
    for (index, i) in s.split('\n').enumerate() {
        write!(stdout,
               "{}{}{}{}",
               Goto(0, (index + 1) as u16),
               index + 1,
               Goto(3, (index + 1) as u16),
               i)
            .unwrap();
    }
}

fn draw_cursor(stdout: &mut termion::raw::RawTerminal<std::io::Stdout>, cx: u16, cy: u16) {
    write!(stdout, "{}", termion::cursor::Goto(cx, cy)).unwrap();
}
<|endoftext|>


<commit_before>#[macro_use] extern crate clap;
#[macro_use] extern crate log;
extern crate env_logger;

mod cli;

fn main() {
    env_logger::init().expect("Failed to initialize logger.");

    run_cli();
}

fn run_cli<'a>() -> Result<(), &'a str> {
    let matches = cli::app().get_matches();

    let verbose_level = match matches.occurrences_of("verbose") {
        0...4 => matches.occurrences_of("verbose"),
        _ => 4,
    };

    match matches.subcommand_name() {
        Some("cd") => println!("CD!"),
        None       => panic!("Subcommand is required, so no idea how we got here!"),
        _          => println!("'{}' is not implemented yet.", matches.subcommand_name().unwrap()),
    };

    Ok(())
}
<commit_msg>Add ability to exit non-zero if run_cli reports a failure<commit_after>#[macro_use] extern crate clap;
#[macro_use] extern crate log;
extern crate env_logger;

mod cli;

use std::process::exit;

fn main() {
    env_logger::init().expect("Failed to initialize logger.");

    match run_cli() {
        Ok(_) => {},
        Err((message, exit_code)) => {
            error!("Error: {}", message);
            exit(exit_code);
        },
    }
}

fn run_cli<'a>() -> Result<(), (&'a str, i32)> {
    let matches = cli::app().get_matches();

    let verbose_level = match matches.occurrences_of("verbose") {
        0...4 => matches.occurrences_of("verbose"),
        _ => 4,
    };

    match matches.subcommand_name() {
        Some("cd") => println!("CD!"),
        None       => panic!("Subcommand is required, so no idea how we got here!"),
        _          => println!("'{}' is not implemented yet.", matches.subcommand_name().unwrap()),
    };

    Ok(())
}
<|endoftext|>


<commit_before>extern crate "dbus-rs" as dbus;

use std::os::args;
use dbus::{Connection, BusType, Message, MessageItem};

static DEST: &'static str = "org.kde.kdeconnect";
static PATH: &'static str = "/modules/kdeconnect";

fn get_ids(c: &Connection) -> Result<Vec<String>, &'static str> {
    let mut m = Message::new_method_call(DEST
                                         , PATH
                                         , [DEST, "daemon"].connect(".").as_slice()
                                         , "devices").unwrap();
    m.append_items(&[MessageItem::Bool(true)]); // onlyReachable
    m = c.send_with_reply_and_block(m, 1000).unwrap();
    let items = m.get_items();
    match items[0] {
        MessageItem::Array(_, 0) => Err("No reachable devices"),
        MessageItem::Array(ref a, _) => Ok(a.iter().map(|&ref e| match *e {
            MessageItem::Str(ref s) => s.clone(),
            _ => unreachable!(),
        }).collect()),
        _ => unreachable!(),
    }
}

fn share_url(c: &Connection, id: &String, url: &String) {
    let mut m = Message::new_method_call(DEST
                                         , [PATH, "devices", id.as_slice(), "share"].connect("/").as_slice()
                                         , [DEST, "device.share"].connect(".").as_slice()
                                         , "shareUrl").unwrap();
    m.append_items(&[MessageItem::Str(url.clone())]);
    c.send_with_reply_and_block(m, 1000).unwrap();
}

fn main() {
    let mut urls = args();
    urls.remove(0);

    let ref c = Connection::get_private(BusType::Session).unwrap();
    let ids = get_ids(c).unwrap();
    for url in urls.iter() {
        for id in ids.iter() {
            share_url(c, id, url);
        }
    }
}
<commit_msg>use new slice syntax<commit_after>extern crate "dbus-rs" as dbus;

use std::os::args;
use dbus::{Connection, BusType, Message, MessageItem};

static DEST: &'static str = "org.kde.kdeconnect";
static PATH: &'static str = "/modules/kdeconnect";

fn get_ids(c: &Connection) -> Result<Vec<String>, &'static str> {
    let mut m = Message::new_method_call(DEST
                                         , PATH
                                         , &[DEST, "daemon"].connect(".")[]
                                         , "devices").unwrap();
    m.append_items(&[MessageItem::Bool(true)]); // onlyReachable
    m = c.send_with_reply_and_block(m, 1000).unwrap();
    let items = m.get_items();
    match items[0] {
        MessageItem::Array(_, 0) => Err("No reachable devices"),
        MessageItem::Array(ref a, _) => Ok(a.iter().map(|&ref e| match *e {
            MessageItem::Str(ref s) => s.clone(),
            _ => unreachable!(),
        }).collect()),
        _ => unreachable!(),
    }
}

fn share_url(c: &Connection, id: &String, url: &String) {
    let mut m = Message::new_method_call(DEST
                                         , &[PATH, "devices", &id[], "share"].connect("/")[]
                                         , &[DEST, "device.share"].connect(".")[]
                                         , "shareUrl").unwrap();
    m.append_items(&[MessageItem::Str(url.clone())]);
    c.send_with_reply_and_block(m, 1000).unwrap();
}

fn main() {
    let urls = &args()[1..];

    let ref c = Connection::get_private(BusType::Session).unwrap();
    let ids = get_ids(c).unwrap();
    for url in urls.iter() {
        for id in ids.iter() {
            share_url(c, id, url);
        }
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate assimp;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;

use assimp::Vector3D;

fn sort_points_by_y(points: &mut Vec<Point>) {
    for _ in 0..(points.len() - 1) {
        for j in 0..(points.len() - 1) {
            if points[j].y() < points[j + 1].y() {
                points.swap(j, j + 1);
            }
        }
    }
}

fn get_line_points(start: Point, end: Point) -> Vec<Point> {
    let mut x0 = start.x();
    let mut y0 = start.y();
    let mut x1 = end.x();
    let mut y1 = end.y();

    let steep = (y1 - y0).abs() > (x1 - x0).abs();

    if steep {
        std::mem::swap(&mut x0, &mut y0);
        std::mem::swap(&mut x1, &mut y1);
    }

    let reverse = x0 > x1;

    if reverse {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }

    let dx = x1 - x0;
    let dy = (y1 - y0).abs();

    let mut err = dx / 2;
    let mut y = y0;
    let ystep = match y0.cmp(&y1) {
        Ordering::Less => 1,
        _ => -1
    };

    let mut points: Vec<Point> = vec![];

    for x in x0..x1 {
        if steep {
            points.push(Point::new(y, x));
        } else {
            points.push(Point::new(x, y));
        }

        err -= dy;

        if err < 0 {
            y += ystep;
            err += dx;
        }
    }

    points
}

trait TinyRenderer {
    fn pixel(&mut self, Point, Color);
    fn line(&mut self, Point, Point, Color);
    fn triangle(&mut self, Point, Point, Point, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, p: Point, c: Color) {
        let current_color = self.draw_color();

        self.set_draw_color(c);
        self.draw_point(p).unwrap();
        self.set_draw_color(current_color);
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let mut x0 = start.x();
        let mut y0 = start.y();
        let mut x1 = end.x();
        let mut y1 = end.y();

        let steep = (y1 - y0).abs() > (x1 - x0).abs();

        if steep {
            std::mem::swap(&mut x0, &mut y0);
            std::mem::swap(&mut x1, &mut y1);
        }

        let reverse = x0 > x1;

        if reverse {
            std::mem::swap(&mut x0, &mut x1);
            std::mem::swap(&mut y0, &mut y1);
        }

        let dx = x1 - x0;
        let dy = (y1 - y0).abs();

        let mut err = dx / 2;
        let mut y = y0;
        let ystep = match y0.cmp(&y1) {
            Ordering::Less => 1,
            _ => -1
        };

        for x in x0..x1 {
            if steep {
                self.draw_point(Point::new(y, x)).unwrap();
            } else {
                self.draw_point(Point::new(x, y)).unwrap();
            }

            err -= dy;

            if err < 0 {
                y += ystep;
                err += dx;
            }
        }

        self.set_draw_color(current_color);
    }

    fn triangle(&mut self, p0: Point, p1: Point, p2: Point, c: Color) {
        let mut points = vec![p0, p1, p2];
        sort_points_by_y(&mut points);

        let horizon = get_line_points(points[1], points[2]);

        for l in 0..horizon.len() {
            self.line(points[0], horizon[l], c);
        }
    }
}

fn main() {
    let (width, height) = (600, 600);
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", width, height)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            for j in 0..3 {
                let v0 = match mesh.get_vertex(face[j]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let v1 = match mesh.get_vertex(face[(j + 1) % 3]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let x0 = width as i32 - ((v0.x + 1.) * width as f32 / 2.) as i32;
                let y0 = height as i32 - ((v0.y + 1.) * height as f32 / 2.) as i32;
                let x1 = width as i32 - ((v1.x + 1.) * width as f32 / 2.) as i32;
                let y1 = height as i32 - ((v1.y + 1.) * height as f32 / 2.) as i32;

                renderer.line(Point::new(x0, y0), Point::new(x1, y1), Color::RGB(255, 255, 255));
            }
        }
    }

    renderer.triangle(Point::new(20, 50), Point::new(100, 200), Point::new(40, 300), Color::RGB(0, 255, 0));

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<commit_msg>Refactored line method.<commit_after>extern crate sdl2;
extern crate assimp;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;

use assimp::Vector3D;

fn sort_points_by_y(points: &mut Vec<Point>) {
    for _ in 0..(points.len() - 1) {
        for j in 0..(points.len() - 1) {
            if points[j].y() < points[j + 1].y() {
                points.swap(j, j + 1);
            }
        }
    }
}

fn get_line_points(start: Point, end: Point) -> Vec<Point> {
    let mut x0 = start.x();
    let mut y0 = start.y();
    let mut x1 = end.x();
    let mut y1 = end.y();

    let steep = (y1 - y0).abs() > (x1 - x0).abs();

    if steep {
        std::mem::swap(&mut x0, &mut y0);
        std::mem::swap(&mut x1, &mut y1);
    }

    let reverse = x0 > x1;

    if reverse {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }

    let dx = x1 - x0;
    let dy = (y1 - y0).abs();

    let mut err = dx / 2;
    let mut y = y0;
    let ystep = match y0.cmp(&y1) {
        Ordering::Less => 1,
        _ => -1
    };

    let mut points: Vec<Point> = vec![];

    for x in x0..x1 {
        if steep {
            points.push(Point::new(y, x));
        } else {
            points.push(Point::new(x, y));
        }

        err -= dy;

        if err < 0 {
            y += ystep;
            err += dx;
        }
    }

    points
}

trait TinyRenderer {
    fn pixel(&mut self, Point, Color);
    fn line(&mut self, Point, Point, Color);
    fn triangle(&mut self, Point, Point, Point, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, p: Point, c: Color) {
        let current_color = self.draw_color();

        self.set_draw_color(c);
        self.draw_point(p).unwrap();
        self.set_draw_color(current_color);
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let points = get_line_points(start, end);

        for p in 0..points.len() {
            self.draw_point(points[p]).unwrap();
        }

        self.set_draw_color(current_color);
    }

    fn triangle(&mut self, p0: Point, p1: Point, p2: Point, c: Color) {
        let mut points = vec![p0, p1, p2];
        sort_points_by_y(&mut points);

        let horizon = get_line_points(points[1], points[2]);

        for l in 0..horizon.len() {
            self.line(points[0], horizon[l], c);
        }
    }
}

fn main() {
    let (width, height) = (600, 600);
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", width, height)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            for j in 0..3 {
                let v0 = match mesh.get_vertex(face[j]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let v1 = match mesh.get_vertex(face[(j + 1) % 3]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let x0 = width as i32 - ((v0.x + 1.) * width as f32 / 2.) as i32;
                let y0 = height as i32 - ((v0.y + 1.) * height as f32 / 2.) as i32;
                let x1 = width as i32 - ((v1.x + 1.) * width as f32 / 2.) as i32;
                let y1 = height as i32 - ((v1.y + 1.) * height as f32 / 2.) as i32;

                renderer.line(Point::new(x0, y0), Point::new(x1, y1), Color::RGB(255, 255, 255));
            }
        }
    }

    renderer.triangle(Point::new(20, 50), Point::new(100, 200), Point::new(40, 300), Color::RGB(0, 255, 0));

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<|endoftext|>


<commit_before>//! goto :: Flexible Working Directory Shortcuts
//!
//! Copyright (c) 2016 by William R. Fraser

extern crate docopt;
extern crate rustc_serialize;
extern crate toml;

use std::collections::btree_map::*;
use std::env;
use std::fs::File;
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use docopt::Docopt;

const CONFIG_FILENAME: &'static str = ".goto.toml";

// 79 columns:
// ----------------------------------------------------------------------------
const USAGE: &'static str = r#"
Usage:
    goto [<name>]
    goto (--help | --version)

Configuration is stored in ~/.goto.toml, with the following format:

    name = "/some/path"             # 'goto name' takes you here
    othername = "~/some/other/path" # $HOME expansion will happen

    ["/somewhere/specific"]         # Only in effect when in this location:
    "*" = "default/under/specific"  # With no arguments, this is used.
    "name" = "somewhere/else"       # Overshadows the one above.

Relative paths under a context header are resolved relative to the path in that
header. In the above example, when your current directory is under
/somewhere/specific, running 'goto name' takes you to
/somewhere/specific/somewhere/else.

goto is meant to be used as the argument to your shell's 'eval' builtin, like:
    function goto() {
        eval $(/usr/local/bin/goto $*)  # or wherever the 'goto' binary is
    }
"#;

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_name: Option<String>,
}

fn read_config(config_path: &Path) -> io::Result<toml::Table> {
    let mut config_text = String::new();
    let mut file = try!(File::open(config_path));
    try!(file.read_to_string(&mut config_text));
    let mut parser = toml::Parser::new(&config_text);
    let config = match parser.parse() {
        Some(v) => v,
        None => {
            let mut msg = String::from("failed to parse TOML:");
            for err in &parser.errors {
                let linecol_lo = parser.to_linecol(err.lo);
                let linecol_hi = parser.to_linecol(err.hi);
                msg.push_str(&format!("\n\t{} at {}:{} to {}:{}",
                        err.desc,
                        linecol_lo.0 + 1,
                        linecol_lo.1 + 1,
                        linecol_hi.0 + 1,
                        linecol_hi.1 + 1));
            }
            return Err(io::Error::new(io::ErrorKind::Other, msg));
        }
    };

    Ok(config)
}

type PathMapping = BTreeMap<String, PathBuf>;

#[derive(Debug)]
struct Configuration {
    global: PathMapping,
    contexts: BTreeMap<PathBuf, PathMapping>,
}

fn parse_toml_as_path(t: &toml::Value, cwd: Option<&Path>) -> Result<PathBuf, String> {
    if let &toml::Value::String(ref s) = t {
        let path: PathBuf = if s.starts_with("~/") {
            env::home_dir().unwrap().join(&Path::new(&s[2..]))
        } else if s.starts_with("/") {
            PathBuf::from(s)
        } else if cwd.is_some() {
            cwd.unwrap().join(Path::new(&s))
        } else {
            return Err(format!("expected a path starting with \"/\" or \"~/\""));
        };
        Ok(path)
    } else {
        Err(format!("type error: expected a string, not {}", t.type_str()))
    }
}

/// Process the parsed configuration TOML into goto's configuration struct.
/// if `cwd` is specified, all relative paths will be interpreted relative to that path.
fn process_config(config_toml: toml::Table, cwd: Option<&Path>) -> Result<Configuration, String> {
    let mut config = Configuration {
        global: PathMapping::new(),
        contexts: BTreeMap::new(),
    };

    for (k, v) in config_toml.into_iter() {
        if let toml::Value::Table(t) = v {
            // A path context.

            let context_path = match parse_toml_as_path(&toml::Value::String(k), cwd) {
                Ok(path) => path,
                Err(msg) => { return Err(format!("error: {}", msg)); }
            };

            let mut context_map = PathMapping::new();

            for (name, path) in t.into_iter() {
                let mapped_path: PathBuf = match parse_toml_as_path(&path, Some(&context_path)) {
                    Ok(path) => path,
                    Err(msg) => {
                        return Err(format!("error at {:?}.{}: {}", context_path, name, msg));
                    }
                };

                context_map.insert(name, mapped_path);
            }

            config.contexts.insert(context_path, context_map);
        } else {
            // A top-level entry. Attempt to parse as a path and insert into the global table.
            match parse_toml_as_path(&v, cwd) {
                Ok(path) => { config.global.insert(k, path); },
                Err(msg) => {
                    return Err(format!(
                        "error at {}: expected a table or a path string, not {} ({})",
                         k, v.type_str(), msg));
                },
            }
        }
    }

    Ok(config)
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| {
                                d.version(Some(format!("goto {}", env!("CARGO_PKG_VERSION"))))
                                 .decode()
                            })
                            .unwrap_or_else(|e| {
                                writeln!(io::stderr(), "{}", e).unwrap();
                                ::std::process::exit(if e.fatal() { 1 } else { 0 });
                            });

    let name = args.arg_name.unwrap_or("*".to_owned());

    let home = env::home_dir().unwrap_or_else(|| {
        panic!("unable to determine home directory");
    });

    let cwd = PathBuf::from(env::current_dir().unwrap_or_else(|e| {
        panic!("unable to get current working directory: {}", e);
    }));

    let config_toml = read_config(&home.join(Path::new(CONFIG_FILENAME))).map_err(|e| {
        panic!("failed to read configuration ~/{}: {}", CONFIG_FILENAME, e);
    }).unwrap();

    let config = process_config(config_toml, Some(&home)).map_err(|msg| {
        panic!("invalid configuration in ~/{}: {}", CONFIG_FILENAME, msg);
    }).unwrap();

    let mut matched = false;
    let mut context_paths_by_len: Vec<&PathBuf> = config.contexts.keys().collect();
    context_paths_by_len.sort_by_key(|p| p.as_os_str().len());
    for context_path in context_paths_by_len.iter().rev() {
        if cwd.starts_with(context_path) {
            let map = config.contexts.get(*context_path).unwrap();
            if let Some(path) = map.get(&name) {
                println!("pushd {:?}", path);
                matched = true;
                break;
            }
        }
    }

    if !matched {
        if let Some(path) = config.global.get(&name) {
            println!("pushd {:?}", path);
            matched = true;
        }
    }

    if !matched {
        writeln!(io::stderr(), "not sure where to go").unwrap();
    }
}
<commit_msg>don't use panic() for routine errors<commit_after>//! goto :: Flexible Working Directory Shortcuts
//!
//! Copyright (c) 2016 by William R. Fraser

extern crate docopt;
extern crate rustc_serialize;
extern crate toml;

use std::collections::btree_map::*;
use std::env;
use std::fs::File;
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use docopt::Docopt;

const CONFIG_FILENAME: &'static str = ".goto.toml";

// 79 columns:
// ----------------------------------------------------------------------------
const USAGE: &'static str = r#"
Usage:
    goto [<name>]
    goto (--help | --version)

Configuration is stored in ~/.goto.toml, with the following format:

    name = "/some/path"             # 'goto name' takes you here
    othername = "~/some/other/path" # $HOME expansion will happen

    ["/somewhere/specific"]         # Only in effect when in this location:
    "*" = "default/under/specific"  # With no arguments, this is used.
    "name" = "somewhere/else"       # Overshadows the one above.

Relative paths under a context header are resolved relative to the path in that
header. In the above example, when your current directory is under
/somewhere/specific, running 'goto name' takes you to
/somewhere/specific/somewhere/else.

goto is meant to be used as the argument to your shell's 'eval' builtin, like:
    function goto() {
        eval $(/usr/local/bin/goto $*)  # or wherever the 'goto' binary is
    }
"#;

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_name: Option<String>,
}

fn read_config(config_path: &Path) -> io::Result<toml::Table> {
    let mut config_text = String::new();
    let mut file = try!(File::open(config_path));
    try!(file.read_to_string(&mut config_text));
    let mut parser = toml::Parser::new(&config_text);
    let config = match parser.parse() {
        Some(v) => v,
        None => {
            let mut msg = String::from("failed to parse TOML:");
            for err in &parser.errors {
                let linecol_lo = parser.to_linecol(err.lo);
                let linecol_hi = parser.to_linecol(err.hi);
                msg.push_str(&format!("\n\t{} at {}:{} to {}:{}",
                        err.desc,
                        linecol_lo.0 + 1,
                        linecol_lo.1 + 1,
                        linecol_hi.0 + 1,
                        linecol_hi.1 + 1));
            }
            return Err(io::Error::new(io::ErrorKind::Other, msg));
        }
    };

    Ok(config)
}

type PathMapping = BTreeMap<String, PathBuf>;

#[derive(Debug)]
struct Configuration {
    global: PathMapping,
    contexts: BTreeMap<PathBuf, PathMapping>,
}

fn parse_toml_as_path(t: &toml::Value, cwd: Option<&Path>) -> Result<PathBuf, String> {
    if let &toml::Value::String(ref s) = t {
        let path: PathBuf = if s.starts_with("~/") {
            env::home_dir().unwrap().join(&Path::new(&s[2..]))
        } else if s.starts_with("/") {
            PathBuf::from(s)
        } else if cwd.is_some() {
            cwd.unwrap().join(Path::new(&s))
        } else {
            return Err(format!("expected a path starting with \"/\" or \"~/\""));
        };
        Ok(path)
    } else {
        Err(format!("type error: expected a string, not {}", t.type_str()))
    }
}

/// Process the parsed configuration TOML into goto's configuration struct.
/// if `cwd` is specified, all relative paths will be interpreted relative to that path.
fn process_config(config_toml: toml::Table, cwd: Option<&Path>) -> Result<Configuration, String> {
    let mut config = Configuration {
        global: PathMapping::new(),
        contexts: BTreeMap::new(),
    };

    for (k, v) in config_toml.into_iter() {
        if let toml::Value::Table(t) = v {
            // A path context.

            let context_path = match parse_toml_as_path(&toml::Value::String(k), cwd) {
                Ok(path) => path,
                Err(msg) => { return Err(format!("error: {}", msg)); }
            };

            let mut context_map = PathMapping::new();

            for (name, path) in t.into_iter() {
                let mapped_path: PathBuf = match parse_toml_as_path(&path, Some(&context_path)) {
                    Ok(path) => path,
                    Err(msg) => {
                        return Err(format!("error at {:?}.{}: {}", context_path, name, msg));
                    }
                };

                context_map.insert(name, mapped_path);
            }

            config.contexts.insert(context_path, context_map);
        } else {
            // A top-level entry. Attempt to parse as a path and insert into the global table.
            match parse_toml_as_path(&v, cwd) {
                Ok(path) => { config.global.insert(k, path); },
                Err(msg) => {
                    return Err(format!(
                        "error at {}: expected a table or a path string, not {} ({})",
                         k, v.type_str(), msg));
                },
            }
        }
    }

    Ok(config)
}

fn exit(msg: String, fatal: bool) -> ! {
    io::stderr().write_all(msg.as_bytes()).unwrap();
    if !msg.ends_with("\n") {
        io::stderr().write_all(b"\n").unwrap();
    }
    let exit_code = if fatal { 1 } else { 0 };
    ::std::process::exit(exit_code);
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| {
                                d.version(Some(format!("goto {}", env!("CARGO_PKG_VERSION"))))
                                 .decode()
                            })
                            .unwrap_or_else(|e| {
                                exit(format!("{}", e), e.fatal());
                            });

    let name = args.arg_name.unwrap_or("*".to_owned());

    let home = env::home_dir().unwrap_or_else(|| {
        exit(format!("unable to determine home directory"), true);
    });

    let cwd = PathBuf::from(env::current_dir().unwrap_or_else(|e| {
        exit(format!("unable to get current working directory: {}", e), true);
    }));

    let config_toml = read_config(&home.join(Path::new(CONFIG_FILENAME))).map_err(|e| {
        exit(format!("failed to read configuration ~/{}: {}", CONFIG_FILENAME, e), true);
    }).unwrap();

    let config = process_config(config_toml, Some(&home)).map_err(|msg| {
        exit(format!("invalid configuration in ~/{}: {}", CONFIG_FILENAME, msg), true);
    }).unwrap();

    let mut matched = false;
    let mut context_paths_by_len: Vec<&PathBuf> = config.contexts.keys().collect();
    context_paths_by_len.sort_by_key(|p| p.as_os_str().len());
    for context_path in context_paths_by_len.iter().rev() {
        if cwd.starts_with(context_path) {
            let map = config.contexts.get(*context_path).unwrap();
            if let Some(path) = map.get(&name) {
                println!("pushd {:?}", path);
                matched = true;
                break;
            }
        }
    }

    if !matched {
        if let Some(path) = config.global.get(&name) {
            println!("pushd {:?}", path);
            matched = true;
        }
    }

    if !matched {
        exit(format!("not sure where to go"), false);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate image;
extern crate nalgebra;
extern crate num;
extern crate getopts;

mod steve_common;
mod steve;
mod steve17;

const VERT_PROG: &'static str = include_str!("vert.glsl");

const FRAG_PROG: &'static str = include_str!("frag.glsl");

use glium::{Surface, VertexBuffer, Frame, Program};
use glium::index::NoIndices;
use glium::texture::srgb_texture2d::SrgbTexture2d;
use glium::uniforms::{MagnifySamplerFilter, Uniforms, AsUniformValue};
use glium::draw_parameters::DepthTest;
use glium::backend::glutin_backend::GlutinFacade;
use glium::index::PrimitiveType;
use glium::vertex::BufferCreationError;
use glium::glutin::{Event, ElementState, VirtualKeyCode};
use std::f32::consts::{FRAC_PI_2, PI};
use std::thread::sleep_ms;
use nalgebra::{Rot3, Iso3, Vec3, Persp3, ToHomogeneous, Mat4};
use num::traits::{Zero, One};
use getopts::Options;
use std::env;

enum NextAction {
    Quit,
}

fn handle_input(turn_rate_y: &mut f32, turn_rate_x: &mut f32, do_anim: &mut bool, state: ElementState, vk_opt: &Option<VirtualKeyCode>) -> Option<NextAction> {
    let mut next_action = None;
    match *vk_opt {
        Some(vk) => match (vk, state) {
            (VirtualKeyCode::Right, ElementState::Pressed)  => *turn_rate_y = PI / 200.0,
            (VirtualKeyCode::Left, ElementState::Pressed)  => *turn_rate_y = -PI / 200.0,
            (VirtualKeyCode::Right, ElementState::Released) => *turn_rate_y = 0.0f32,
            (VirtualKeyCode::Left, ElementState::Released) => *turn_rate_y = 0.0f32,

            (VirtualKeyCode::Up, ElementState::Pressed)  => *turn_rate_x = PI / 200.0,
            (VirtualKeyCode::Down, ElementState::Pressed)  => *turn_rate_x = -PI / 200.0,
            (VirtualKeyCode::Up, ElementState::Released) => *turn_rate_x = 0.0f32,
            (VirtualKeyCode::Down, ElementState::Released) => *turn_rate_x = 0.0f32,

            (VirtualKeyCode::A, ElementState::Released) => *do_anim = !*do_anim,

            (VirtualKeyCode::Q, ElementState::Released) => next_action =  Some(NextAction::Quit),
            _ => ()
        },
        None => ()
    };
    next_action
}

pub struct ModelPiece {
    vbo: VertexBuffer<steve_common::Vertex>,
    prim: PrimitiveType,
    bone: Option<Vec3<f32>>,
}

impl ModelPiece {
    fn new(display: &GlutinFacade, verts: &[steve_common::Vertex], prim: PrimitiveType, bone: Option<Vec3<f32>>) -> Result<Self, BufferCreationError> {
        let vertex_buffer = match VertexBuffer::new(display, verts) {
            Ok(vbo) => vbo,
            Err(e) => return Err(e),
        };
        Ok(ModelPiece{vbo: vertex_buffer, prim: prim, bone: bone})
    }

    fn make_anim_matrix(self: &Self, anim_angle: f32) -> Mat4<f32> {
        match self.bone {
            Some(bone) => {
                let trans1 = Iso3::new(-bone, Vec3::zero()).to_homogeneous();
                let rot3 = Rot3::new(Vec3::new(0.0, anim_angle, 0.0)).to_homogeneous();
                let trans2 = Iso3::new(bone, Vec3::zero()).to_homogeneous();
                trans2 * rot3 * trans1},
            None => Mat4::<f32>::one()
        }
    }

    fn draw<U>(self: &Self, target: &mut Frame, shader_prog: &Program, uniforms: &U, params: &glium::draw_parameters::DrawParameters) where U: Uniforms {
        let ibo = NoIndices(self.prim);
        target.draw(&self.vbo, ibo, shader_prog, uniforms, params).unwrap();
    }
}

macro_rules! implement_uniforms {
    ($struct_name:ident, $($field_name:ident),+) => (
        impl<'b> glium::uniforms::Uniforms for $struct_name<'b> {
            #[inline]
            fn visit_values<'a, F: FnMut(&str, glium::uniforms::UniformValue<'a>)>(&'a self, mut output: F) {
                $(
                    output(stringify!($field_name), self.$field_name.as_uniform_value());
                )+
            }
        }
    );

    ($struct_name:ident, $($field_name:ident),+,) => (
        implement_uniforms!($struct_name, $($field_name),+);
    );
}

#[derive(Copy, Clone)]
struct PlayerModelUniforms<'a> {
    model: Mat4<f32>,
    view:  Mat4<f32>,
    projection:  Mat4<f32>,
    tex: &'a glium::uniforms::Sampler<'a, SrgbTexture2d>,
}

implement_uniforms!(PlayerModelUniforms, model, view, projection, tex);

pub struct PlayerModel {
    head: ModelPiece,
    torso: ModelPiece,

    larm: ModelPiece,
    rarm: ModelPiece,

    lleg: ModelPiece,
    rleg: ModelPiece,

    texture: SrgbTexture2d,
}

impl PlayerModel {
    fn draw(self: &Self, target: &mut Frame, shader_prog: &Program, t: f32, angle_y: f32, angle_x: f32) {
        let perspective = {
            let (width, height) = target.get_dimensions();
            let aspect_ratio = width as f32 / height as f32;
            //println!("Aspect ratio: {} ({} x {})", aspect_ratio, height, width);

            let fov: f32 = 3.141592 / 3.0;
            let zfar = 1024.0;
            let znear = 0.1;

            Persp3::new(aspect_ratio, fov, znear, zfar).to_mat()
        };

        let rot1 = Rot3::new(Vec3::new(-FRAC_PI_2, 0.0, 0.0)).to_homogeneous();
        let rot2 = Rot3::new(Vec3::new(0.0, FRAC_PI_2, 0.0)).to_homogeneous();

        let trans_final = Vec3::new(0.0, 0.0, 100.0);
        let trans_final_mat = Iso3::new(trans_final, Vec3::zero()).to_homogeneous();
        let inv_trans_final_mat = Iso3::new(-trans_final, Vec3::zero()).to_homogeneous();

        let model = trans_final_mat * rot2 * rot1;
        let view_rot1 = Rot3::new(Vec3::new(0.0, angle_y, 0.0)).to_homogeneous();
        let view_rot2 = Rot3::new(Vec3::new(angle_x, 0.0, 0.0)).to_homogeneous();
        let view = trans_final_mat * view_rot2 * view_rot1 * inv_trans_final_mat;

        let mut uniforms = PlayerModelUniforms{
            model: model,
            view: view,
            projection: perspective,
            tex: &self.texture.sampled().magnify_filter(MagnifySamplerFilter::Nearest),
        };

        let params = glium::DrawParameters {
            depth: glium::Depth {
                test: DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };

        self.head.draw(target, shader_prog, &uniforms, &params);
        self.torso.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.larm.make_anim_matrix(-FRAC_PI_2 * t.sin());
        let model = trans_final_mat * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.larm.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.rarm.make_anim_matrix(FRAC_PI_2 * t.sin());
        let model = trans_final_mat * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.rarm.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.lleg.make_anim_matrix(FRAC_PI_2 * t.sin());
        let model = trans_final_mat * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.lleg.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.rleg.make_anim_matrix(-FRAC_PI_2 * t.sin());
        let model = trans_final_mat * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.rleg.draw(target, shader_prog, &uniforms, &params);
    }
}

fn mainloop(display: &GlutinFacade, skinfile: Option<String>, mc17: bool) {
    use std::io::Cursor;
    use std::fs::File;

    let image = match skinfile {
        Some(filename) =>
        {
            let image_file = File::open(filename).unwrap();
            image::load(&image_file,
                        image::PNG).unwrap()
        },
        None => image::load(Cursor::new(&include_bytes!("steve.png")[..]),
                            image::PNG).unwrap()
    };

    let player = if mc17 {
        PlayerModel{
            head: ModelPiece::new(display, &steve17::HEAD, PrimitiveType::TrianglesList, None).unwrap(),
            torso: ModelPiece::new(display, &steve17::TORSO, PrimitiveType::TrianglesList, None).unwrap(),

            larm: ModelPiece::new(display, &steve17::LARM, PrimitiveType::TrianglesList, Some(*steve17::LARM_BONE)).unwrap(),
            rarm: ModelPiece::new(display, &steve17::RARM, PrimitiveType::TrianglesList, Some(*steve17::RARM_BONE)).unwrap(),

            lleg: ModelPiece::new(display, &steve17::LLEG, PrimitiveType::TrianglesList, Some(*steve17::LLEG_BONE)).unwrap(),
            rleg: ModelPiece::new(display, &steve17::RLEG, PrimitiveType::TrianglesList, Some(*steve17::RLEG_BONE)).unwrap(),

            texture: SrgbTexture2d::new(display, image).unwrap(),
        }
    } else {
        PlayerModel{
            head: ModelPiece::new(display, &steve::HEAD, PrimitiveType::TrianglesList, None).unwrap(),
            torso: ModelPiece::new(display, &steve::TORSO, PrimitiveType::TrianglesList, None).unwrap(),

            larm: ModelPiece::new(display, &steve::LARM, PrimitiveType::TrianglesList, Some(*steve::LARM_BONE)).unwrap(),
            rarm: ModelPiece::new(display, &steve::RARM, PrimitiveType::TrianglesList, Some(*steve::RARM_BONE)).unwrap(),

            lleg: ModelPiece::new(display, &steve::LLEG, PrimitiveType::TrianglesList, Some(*steve::LLEG_BONE)).unwrap(),
            rleg: ModelPiece::new(display, &steve::RLEG, PrimitiveType::TrianglesList, Some(*steve::RLEG_BONE)).unwrap(),

            texture: SrgbTexture2d::new(display, image).unwrap(),
        }
    };

    let shader_prog = Program::from_source(display, VERT_PROG, FRAG_PROG, None).unwrap();

    let mut t = 0.0f32;
    let mut angle_y = 0.0f32;
    let mut angle_x = 0.0f32;

    let anim_rate = 0.04f32;
    let mut turn_rate_y = 0.0f32;
    let mut turn_rate_x = 0.0f32;

    let mut do_anim = true;

    loop {
        if do_anim {
            t += anim_rate;
        }
        angle_y += turn_rate_y;
        angle_x += turn_rate_x;

        for ev in display.poll_events() {
            match ev {
                Event::Closed => return,
                Event::KeyboardInput(state, _, vk_opt) => match handle_input(&mut turn_rate_y, &mut turn_rate_x, &mut do_anim, state, &vk_opt) {
                    Some(NextAction::Quit) => return,
                    None => ()
                },
                _ => ()
            }
        }

        //let (width, height) = display.get_framebuffer_dimensions();
        //println!("Framebuffer dimensions: {} x {}", width, height);
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 1.0, 1.0), 1.0);

        player.draw(&mut target, &shader_prog, t, angle_y, angle_x);

        target.finish().unwrap();
        sleep_ms(16);
    }
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    use glium::{DisplayBuild, GliumCreationError};
    use glium::glutin::{WindowBuilder, GlRequest, Api, GlProfile};

    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optopt("s", "skin", "set skin file", "SKINFILE");
    opts.optflag("m", "mc17", "use Minecraft 1.7 skin layout");
    opts.optflag("h", "help", "print help (what you're looking at right now)");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            println!("{}", f.to_string());
            print_usage(&program, opts);
            std::process::exit(1);
            return;
        }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let mc17 = matches.opt_present("m");
    let skinfile = matches.opt_str("s");

    let display_option = WindowBuilder::new()
        .with_gl(GlRequest::Specific(Api::OpenGl, (3, 3)))
        .with_gl_profile(GlProfile::Core)
        .with_depth_buffer(24)
        .with_vsync()
        .build_glium();
    println!("If there was a message about an error just now, ignore it.  I think the driver's on crack.");
    match display_option {
        Ok(display) => mainloop(&display, skinfile, mc17),
        Err(creation_error) => match creation_error {
            GliumCreationError::BackendCreationError(_) => println!("Oh, crap!"),
            GliumCreationError::IncompatibleOpenGl(msg) => println!("Incompatible OpenGL: {}", msg)
        }
    }
}
<commit_msg>Mouse control<commit_after>#[macro_use]
extern crate glium;
extern crate image;
extern crate nalgebra;
extern crate num;
extern crate getopts;

mod steve_common;
mod steve;
mod steve17;

const VERT_PROG: &'static str = include_str!("vert.glsl");

const FRAG_PROG: &'static str = include_str!("frag.glsl");

use glium::{Surface, VertexBuffer, Frame, Program};
use glium::index::NoIndices;
use glium::texture::srgb_texture2d::SrgbTexture2d;
use glium::uniforms::{MagnifySamplerFilter, Uniforms, AsUniformValue};
use glium::draw_parameters::DepthTest;
use glium::backend::glutin_backend::GlutinFacade;
use glium::index::PrimitiveType;
use glium::vertex::BufferCreationError;
use glium::glutin::{Event, ElementState, VirtualKeyCode, MouseButton};
use std::f32::consts::{FRAC_PI_2, PI};
use std::thread::sleep_ms;
use nalgebra::{Rot3, Iso3, Vec3, Persp3, ToHomogeneous, Mat4};
use num::traits::{Zero, One};
use getopts::Options;
use std::env;

enum NextAction {
    Quit,
}

fn handle_input(turn_rate_y: &mut f32, turn_rate_x: &mut f32, do_anim: &mut bool, state: ElementState, vk_opt: &Option<VirtualKeyCode>) -> Option<NextAction> {
    let mut next_action = None;
    match *vk_opt {
        Some(vk) => match (vk, state) {
            (VirtualKeyCode::Right, ElementState::Pressed)  => *turn_rate_y = PI / 200.0,
            (VirtualKeyCode::Left, ElementState::Pressed)  => *turn_rate_y = -PI / 200.0,
            (VirtualKeyCode::Right, ElementState::Released) => *turn_rate_y = 0.0f32,
            (VirtualKeyCode::Left, ElementState::Released) => *turn_rate_y = 0.0f32,

            (VirtualKeyCode::Up, ElementState::Pressed)  => *turn_rate_x = PI / 200.0,
            (VirtualKeyCode::Down, ElementState::Pressed)  => *turn_rate_x = -PI / 200.0,
            (VirtualKeyCode::Up, ElementState::Released) => *turn_rate_x = 0.0f32,
            (VirtualKeyCode::Down, ElementState::Released) => *turn_rate_x = 0.0f32,

            (VirtualKeyCode::A, ElementState::Released) => *do_anim = !*do_anim,

            (VirtualKeyCode::Q, ElementState::Released) => next_action =  Some(NextAction::Quit),
            _ => ()
        },
        None => ()
    };
    next_action
}

struct MouseState {
    left_pressed: bool,
    position: Option<(i32, i32)>,
}

fn handle_mouse_button(button: MouseButton, state: ElementState, mouse_state: &mut MouseState) {
    match (button, state) {
        (MouseButton::Left, ElementState::Pressed) => mouse_state.left_pressed = true,
        (MouseButton::Left, ElementState::Released) => {
            mouse_state.left_pressed = false;
            mouse_state.position = None;
        },
        _ => ()
    }
}

fn handle_mouse_motion(position: (i32, i32), mouse_state: &mut MouseState, angle_y: &mut f32, angle_x: &mut f32) {
    let (nx, ny) = position;
    match (mouse_state.left_pressed, mouse_state.position) {
        (true, Some((x, y))) => {
            let (dx, dy) = (nx - x, ny - y);
            *angle_y += dx as f32 / 100.0;
            *angle_x -= dy as f32 / 100.0;
            mouse_state.position = Some((nx, ny));
        },
        (true, None) => mouse_state.position = Some((nx, ny)),
        _ => ()
    }
}

pub struct ModelPiece {
    vbo: VertexBuffer<steve_common::Vertex>,
    prim: PrimitiveType,
    bone: Option<Vec3<f32>>,
}

impl ModelPiece {
    fn new(display: &GlutinFacade, verts: &[steve_common::Vertex], prim: PrimitiveType, bone: Option<Vec3<f32>>) -> Result<Self, BufferCreationError> {
        let vertex_buffer = match VertexBuffer::new(display, verts) {
            Ok(vbo) => vbo,
            Err(e) => return Err(e),
        };
        Ok(ModelPiece{vbo: vertex_buffer, prim: prim, bone: bone})
    }

    fn make_anim_matrix(self: &Self, anim_angle: f32) -> Mat4<f32> {
        match self.bone {
            Some(bone) => {
                let trans1 = Iso3::new(-bone, Vec3::zero()).to_homogeneous();
                let rot3 = Rot3::new(Vec3::new(0.0, anim_angle, 0.0)).to_homogeneous();
                let trans2 = Iso3::new(bone, Vec3::zero()).to_homogeneous();
                trans2 * rot3 * trans1},
            None => Mat4::<f32>::one()
        }
    }

    fn draw<U>(self: &Self, target: &mut Frame, shader_prog: &Program, uniforms: &U, params: &glium::draw_parameters::DrawParameters) where U: Uniforms {
        let ibo = NoIndices(self.prim);
        target.draw(&self.vbo, ibo, shader_prog, uniforms, params).unwrap();
    }
}

macro_rules! implement_uniforms {
    ($struct_name:ident, $($field_name:ident),+) => (
        impl<'b> glium::uniforms::Uniforms for $struct_name<'b> {
            #[inline]
            fn visit_values<'a, F: FnMut(&str, glium::uniforms::UniformValue<'a>)>(&'a self, mut output: F) {
                $(
                    output(stringify!($field_name), self.$field_name.as_uniform_value());
                )+
            }
        }
    );

    ($struct_name:ident, $($field_name:ident),+,) => (
        implement_uniforms!($struct_name, $($field_name),+);
    );
}

#[derive(Copy, Clone)]
struct PlayerModelUniforms<'a> {
    model: Mat4<f32>,
    view:  Mat4<f32>,
    projection:  Mat4<f32>,
    tex: &'a glium::uniforms::Sampler<'a, SrgbTexture2d>,
}

implement_uniforms!(PlayerModelUniforms, model, view, projection, tex);

pub struct PlayerModel {
    head: ModelPiece,
    torso: ModelPiece,

    larm: ModelPiece,
    rarm: ModelPiece,

    lleg: ModelPiece,
    rleg: ModelPiece,

    texture: SrgbTexture2d,
}

impl PlayerModel {
    fn draw(self: &Self, target: &mut Frame, shader_prog: &Program, t: f32, angle_y: f32, angle_x: f32) {
        let perspective = {
            let (width, height) = target.get_dimensions();
            let aspect_ratio = width as f32 / height as f32;
            //println!("Aspect ratio: {} ({} x {})", aspect_ratio, height, width);

            let fov: f32 = 3.141592 / 3.0;
            let zfar = 1024.0;
            let znear = 0.1;

            Persp3::new(aspect_ratio, fov, znear, zfar).to_mat()
        };

        let rot1 = Rot3::new(Vec3::new(-FRAC_PI_2, 0.0, 0.0)).to_homogeneous();
        let rot2 = Rot3::new(Vec3::new(0.0, FRAC_PI_2, 0.0)).to_homogeneous();

        let trans_final = Vec3::new(0.0, 0.0, 100.0);
        let trans_final_mat = Iso3::new(trans_final, Vec3::zero()).to_homogeneous();
        let inv_trans_final_mat = Iso3::new(-trans_final, Vec3::zero()).to_homogeneous();

        let model = trans_final_mat * rot2 * rot1;
        let view_rot1 = Rot3::new(Vec3::new(0.0, angle_y, 0.0)).to_homogeneous();
        let view_rot2 = Rot3::new(Vec3::new(angle_x, 0.0, 0.0)).to_homogeneous();
        let view = trans_final_mat * view_rot2 * view_rot1 * inv_trans_final_mat;

        let mut uniforms = PlayerModelUniforms{
            model: model,
            view: view,
            projection: perspective,
            tex: &self.texture.sampled().magnify_filter(MagnifySamplerFilter::Nearest),
        };

        let params = glium::DrawParameters {
            depth: glium::Depth {
                test: DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };

        self.head.draw(target, shader_prog, &uniforms, &params);
        self.torso.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.larm.make_anim_matrix(-FRAC_PI_2 * t.sin());
        let model = trans_final_mat * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.larm.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.rarm.make_anim_matrix(FRAC_PI_2 * t.sin());
        let model = trans_final_mat * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.rarm.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.lleg.make_anim_matrix(FRAC_PI_2 * t.sin());
        let model = trans_final_mat * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.lleg.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.rleg.make_anim_matrix(-FRAC_PI_2 * t.sin());
        let model = trans_final_mat * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.rleg.draw(target, shader_prog, &uniforms, &params);
    }
}

fn mainloop(display: &GlutinFacade, skinfile: Option<String>, mc17: bool) {
    use std::io::Cursor;
    use std::fs::File;

    let image = match skinfile {
        Some(filename) =>
        {
            let image_file = File::open(filename).unwrap();
            image::load(&image_file,
                        image::PNG).unwrap()
        },
        None => image::load(Cursor::new(&include_bytes!("steve.png")[..]),
                            image::PNG).unwrap()
    };

    let player = if mc17 {
        PlayerModel{
            head: ModelPiece::new(display, &steve17::HEAD, PrimitiveType::TrianglesList, None).unwrap(),
            torso: ModelPiece::new(display, &steve17::TORSO, PrimitiveType::TrianglesList, None).unwrap(),

            larm: ModelPiece::new(display, &steve17::LARM, PrimitiveType::TrianglesList, Some(*steve17::LARM_BONE)).unwrap(),
            rarm: ModelPiece::new(display, &steve17::RARM, PrimitiveType::TrianglesList, Some(*steve17::RARM_BONE)).unwrap(),

            lleg: ModelPiece::new(display, &steve17::LLEG, PrimitiveType::TrianglesList, Some(*steve17::LLEG_BONE)).unwrap(),
            rleg: ModelPiece::new(display, &steve17::RLEG, PrimitiveType::TrianglesList, Some(*steve17::RLEG_BONE)).unwrap(),

            texture: SrgbTexture2d::new(display, image).unwrap(),
        }
    } else {
        PlayerModel{
            head: ModelPiece::new(display, &steve::HEAD, PrimitiveType::TrianglesList, None).unwrap(),
            torso: ModelPiece::new(display, &steve::TORSO, PrimitiveType::TrianglesList, None).unwrap(),

            larm: ModelPiece::new(display, &steve::LARM, PrimitiveType::TrianglesList, Some(*steve::LARM_BONE)).unwrap(),
            rarm: ModelPiece::new(display, &steve::RARM, PrimitiveType::TrianglesList, Some(*steve::RARM_BONE)).unwrap(),

            lleg: ModelPiece::new(display, &steve::LLEG, PrimitiveType::TrianglesList, Some(*steve::LLEG_BONE)).unwrap(),
            rleg: ModelPiece::new(display, &steve::RLEG, PrimitiveType::TrianglesList, Some(*steve::RLEG_BONE)).unwrap(),

            texture: SrgbTexture2d::new(display, image).unwrap(),
        }
    };

    let shader_prog = Program::from_source(display, VERT_PROG, FRAG_PROG, None).unwrap();

    let mut t = 0.0f32;
    let mut angle_y = 0.0f32;
    let mut angle_x = 0.0f32;

    let anim_rate = 0.04f32;
    let mut turn_rate_y = 0.0f32;
    let mut turn_rate_x = 0.0f32;

    let mut do_anim = true;

    let mut mouse_state = MouseState{
        left_pressed: false,
        position: None,
    };

    loop {
        if do_anim {
            t += anim_rate;
        }
        angle_y += turn_rate_y;
        angle_x += turn_rate_x;

        for ev in display.poll_events() {
            match ev {
                Event::Closed => return,
                Event::KeyboardInput(state, _, vk_opt) => match handle_input(&mut turn_rate_y, &mut turn_rate_x, &mut do_anim, state, &vk_opt) {
                    Some(NextAction::Quit) => return,
                    None => ()
                },
                Event::MouseInput(state, button) => handle_mouse_button(button, state, &mut mouse_state),
                Event::MouseMoved((x, y)) => handle_mouse_motion((x, y), &mut mouse_state, &mut angle_y, &mut angle_x),
                _ => ()
            }
        }

        //let (width, height) = display.get_framebuffer_dimensions();
        //println!("Framebuffer dimensions: {} x {}", width, height);
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 1.0, 1.0), 1.0);

        player.draw(&mut target, &shader_prog, t, angle_y, angle_x);

        target.finish().unwrap();
        sleep_ms(16);
    }
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    use glium::{DisplayBuild, GliumCreationError};
    use glium::glutin::{WindowBuilder, GlRequest, Api, GlProfile};

    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optopt("s", "skin", "set skin file", "SKINFILE");
    opts.optflag("m", "mc17", "use Minecraft 1.7 skin layout");
    opts.optflag("h", "help", "print help (what you're looking at right now)");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            println!("{}", f.to_string());
            print_usage(&program, opts);
            std::process::exit(1);
        }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let mc17 = matches.opt_present("m");
    let skinfile = matches.opt_str("s");

    let display_option = WindowBuilder::new()
        .with_gl(GlRequest::Specific(Api::OpenGl, (3, 3)))
        .with_gl_profile(GlProfile::Core)
        .with_depth_buffer(24)
        .with_vsync()
        .build_glium();
    println!("If there was a message about an error just now, ignore it.  I think the driver's on crack.");
    match display_option {
        Ok(display) => mainloop(&display, skinfile, mc17),
        Err(creation_error) => match creation_error {
            GliumCreationError::BackendCreationError(_) => println!("Oh, crap!"),
            GliumCreationError::IncompatibleOpenGl(msg) => println!("Incompatible OpenGL: {}", msg)
        }
    }
}
<|endoftext|>