<commit_before>extern crate rand;
extern crate hyper;

use std::fs::{File, OpenOptions, remove_file};
use std::str::FromStr;
use std::path::Path;

mod pasteid;
use pasteid::PasteID;

use std::io;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::*;

const ID_SIZE: usize = 8;
const USAGE: &'static [u8] = b"
pastabin 0.0.1 - Minimal pastebin clone in Rust. Manual post required. CLI recommended.

    USAGE

      POST /

        accepts raw data in the body of the request and responds with a URL of
        a page containing the body's content

      GET /<id>

        retrieves the content for the paste with id `<id>`

    EXAMPLE

        Upload a file:

            curl --data-binary @file.txt https://pasta.lol/

        Upload from stdin:

            echo \"Hellow, World\" | curl --data-binary @- https://pasta.lol/

        Delete an existing paste:

            curl -X DELETE https://pasta.lol/<id>

    SOURCE CODE

        https://github.com/nopjmp/pastabin

    LICENSE

        MIT License. https://github.com/nopjmp/pastabin/blob/master/LICENSE.md
    ";

fn retrieve_paste(id: PasteID) -> Option<File> {
    File::open(&id.filename()).ok()
}

fn create_paste(id: &PasteID) -> io::Result<File> {
    OpenOptions::new()
        .write(true)
        .create_new(true)
        .open(&id.filename())
}

macro_rules! try_handle {
    ($res:ident, $e:expr, $statuscode:expr) => {{
        match $e.ok() {
            Some(v) => v,
            None => {
                *$res.status_mut() = $statuscode;
                return;
            },
        }
    }}
}

fn handle(mut req: Request, mut res: Response) {
    match req.method {
        hyper::Get => {
            match req.uri.clone() {
                AbsolutePath(path) => {
                    if path == "/" {
                        res.headers_mut().set(ContentType::plaintext());
                        res.send(USAGE).unwrap();
                    } else if path == "/favicon.ico" {
                        // todo favicon
                        *res.status_mut() = StatusCode::NotFound;
                    } else if let Ok(id) = PasteID::from_str(path.trim_left_matches("/")) {
                        match retrieve_paste(id) {
                            Some(mut file) => {
                                let metadata = try_handle!(res,
                                                           file.metadata(),
                                                           StatusCode::InternalServerError);
                                res.headers_mut().set(ContentLength(metadata.len()));
                                res.headers_mut().set(ContentType::plaintext());
                                io::copy(&mut file, &mut res.start().unwrap()).unwrap();
                            }
                            None => *res.status_mut() = StatusCode::NotFound,
                        }
                    } else {
                        *res.status_mut() = StatusCode::BadRequest;
                    }
                }
                _ => *res.status_mut() = StatusCode::BadRequest,
            }
        }
        hyper::Post => {
            match req.uri.clone() {
                AbsolutePath(path) => {
                    if path != "/" {
                        *res.status_mut() = StatusCode::BadRequest;
                    } else {
                        let mut tries = 0;
                        let mut id = PasteID::new(ID_SIZE);
                        let mut file = create_paste(&id);
                        while file.is_err() && tries < 3 {
                            id = PasteID::new(ID_SIZE);
                            file = create_paste(&id);
                            tries += 1;
                        }
                        if file.is_err() {
                            *res.status_mut() = StatusCode::InternalServerError;
                        } else {
                            try_handle!(res,
                                        io::copy(&mut req,
                                                 &mut try_handle!(res,
                                                                  file,
                                                                  StatusCode::InternalServerError)),
                                        StatusCode::InternalServerError);
                            *res.status_mut() = StatusCode::Created;
                            res.send(format!("https://pasta.lol/{}\n", id).as_bytes())
                                .unwrap();
                        }
                    }
                }
                _ => *res.status_mut() = StatusCode::BadRequest,
            }
        }
        hyper::Delete => {
            match req.uri.clone() {
                AbsolutePath(path) => {
                    let id = try_handle!(res,
                                         PasteID::from_str(path.trim_left_matches("/")),
                                         StatusCode::BadRequest);
                    let filename = id.filename();
                    let path = Path::new(&filename);
                    if path.exists() {
                        try_handle!(res, remove_file(path), StatusCode::InternalServerError);
                    } else {
                        *res.status_mut() = StatusCode::NotFound;
                    }
                }
                _ => *res.status_mut() = StatusCode::BadRequest,
            }
        }
        _ => *res.status_mut() = StatusCode::MethodNotAllowed,
    }
}

fn main() {
    let mut server = Server::http("127.0.0.1:8080").unwrap();
    server.keep_alive(None);
    let _guard = server.handle(handle);
}
<commit_msg>switch to match cases<commit_after>extern crate rand;
extern crate hyper;

use std::fs::{File, OpenOptions, remove_file};
use std::str::FromStr;
use std::path::Path;

mod pasteid;
use pasteid::PasteID;

use std::io;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::*;

const ID_SIZE: usize = 8;
const USAGE: &'static [u8] = b"
pastabin 0.0.1 - Minimal pastebin clone in Rust. Manual post required. CLI recommended.

    USAGE

      POST /

        accepts raw data in the body of the request and responds with a URL of
        a page containing the body's content

      GET /<id>

        retrieves the content for the paste with id `<id>`

    EXAMPLE

        Upload a file:

            curl --data-binary @file.txt https://pasta.lol/

        Upload from stdin:

            echo \"Hellow, World\" | curl --data-binary @- https://pasta.lol/

        Delete an existing paste:

            curl -X DELETE https://pasta.lol/<id>

    SOURCE CODE

        https://github.com/nopjmp/pastabin

    LICENSE

        MIT License. https://github.com/nopjmp/pastabin/blob/master/LICENSE.md
    ";

fn retrieve_paste(id: PasteID) -> Option<File> {
    File::open(&id.filename()).ok()
}

fn create_paste(id: &PasteID) -> io::Result<File> {
    OpenOptions::new()
        .write(true)
        .create_new(true)
        .open(&id.filename())
}

macro_rules! try_handle {
    ($res:ident, $e:expr, $statuscode:expr) => {{
        match $e.ok() {
            Some(v) => v,
            None => {
                *$res.status_mut() = $statuscode;
                return;
            },
        }
    }}
}

fn handle(mut req: Request, mut res: Response) {
    match req.method {
        hyper::Get => {
            match req.uri.clone() {
                AbsolutePath(path) => {
                    match &*path {
                        "/" => {
                            res.headers_mut().set(ContentType::plaintext());
                            res.send(USAGE).unwrap();
                        }
                        "/favicon.ico" => {
                            // todo favicon
                            *res.status_mut() = StatusCode::NotFound;
                        }
                        _ => {
                            if let Ok(id) = PasteID::from_str(path.trim_left_matches("/")) {
                                match retrieve_paste(id) {
                                    Some(mut file) => {
                                        let metadata = try_handle!(res,
                                                                   file.metadata(),
                                                                   StatusCode::InternalServerError);
                                        res.headers_mut().set(ContentLength(metadata.len()));
                                        res.headers_mut().set(ContentType::plaintext());
                                        io::copy(&mut file, &mut res.start().unwrap()).unwrap();
                                    }
                                    None => *res.status_mut() = StatusCode::NotFound,
                                }
                            } else {
                                *res.status_mut() = StatusCode::BadRequest;
                            }
                        }
                    }
                }
                _ => *res.status_mut() = StatusCode::BadRequest,
            }
        }
        hyper::Post => {
            match req.uri.clone() {
                AbsolutePath(path) => {
                    match &*path {
                        "/" => {
                            let mut tries = 0;
                            let mut id = PasteID::new(ID_SIZE);
                            let mut file = create_paste(&id);
                            while file.is_err() && tries < 3 {
                                id = PasteID::new(ID_SIZE);
                                file = create_paste(&id);
                                tries += 1;
                            }
                            if file.is_err() {
                                *res.status_mut() = StatusCode::InternalServerError;
                            } else {
                                try_handle!(res,
                                        io::copy(&mut req,
                                                 &mut try_handle!(res,
                                                                  file,
                                                                  StatusCode::InternalServerError)),
                                        StatusCode::InternalServerError);
                                *res.status_mut() = StatusCode::Created;
                                res.send(format!("https://pasta.lol/{}\n", id).as_bytes())
                                    .unwrap();
                            }
                        }
                        _ => {
                            *res.status_mut() = StatusCode::BadRequest;
                        }
                    }
                }
                _ => *res.status_mut() = StatusCode::BadRequest,
            }
        }
        hyper::Delete => {
            match req.uri.clone() {
                AbsolutePath(path) => {
                    // TODO: authentication
                    let id = try_handle!(res,
                                         PasteID::from_str(path.trim_left_matches("/")),
                                         StatusCode::BadRequest);
                    let filename = id.filename();
                    let path = Path::new(&filename);
                    if path.exists() {
                        try_handle!(res, remove_file(path), StatusCode::InternalServerError);
                    } else {
                        *res.status_mut() = StatusCode::NotFound;
                    }
                }
                _ => *res.status_mut() = StatusCode::BadRequest,
            }
        }
        _ => *res.status_mut() = StatusCode::MethodNotAllowed,
    }
}

fn main() {
    let mut server = Server::http("127.0.0.1:8080").unwrap();
    server.keep_alive(None);
    let _guard = server.handle(handle);
}
<|endoftext|>


<commit_before>#![feature(slicing_syntax)]

mod board;

#[cfg(not(test))]
fn main() {
  let mut brd = board::Board::new(65, 248).random();
  let mut timer = std::io::Timer::new().unwrap();
  let ref mut worker_pool = board::WorkerPool::new_with_default_size();
  let periodic = timer.periodic(std::time::Duration::milliseconds(64));
  loop {
    println!("\x1b[H\x1b[2J{}", brd);
    periodic.recv();
    brd = brd.parallel_next_generation(worker_pool);
  }
}
<commit_msg>Make sure the clock didn't hang up somehow.<commit_after>#![feature(slicing_syntax)]

mod board;

#[cfg(not(test))]
fn main() {
  let mut brd = board::Board::new(65, 248).random();
  let mut timer = std::io::Timer::new().unwrap();
  let ref mut worker_pool = board::WorkerPool::new_with_default_size();
  let periodic = timer.periodic(std::time::Duration::milliseconds(64));
  loop {
    println!("\x1b[H\x1b[2J{}", brd);
    periodic.recv().unwrap();
    brd = brd.parallel_next_generation(worker_pool);
  }
}
<|endoftext|>


<commit_before>FAIL
#[macro_use] extern crate lazy_static;
extern crate regex;
extern crate json;

use std::env;
use std::io;
use std::io::*;
use std::process;

mod dictionary;
mod ansi;

fn main() {
    let arguments: Vec<String> = env::args().collect();
    let action = env::args().nth(1);
    let include_ids = arguments.contains(&"--id".to_string());
    let tag_per_line = arguments.contains(&"--tag-per-line".to_string());
    let color = arguments.contains(&"--color".to_string());

    match action.as_ref().map(String::as_ref) {
        Some("decode") => process_stdin(include_ids, tag_per_line, color),
        Some(a) => die(&format!("unsupported action '{}'", &a)),
        None => die("Usage: transfix decode"),
    }
}

fn process_stdin(include_ids: bool, tag_per_line: bool, color: bool) {
    let stdin = io::stdin();
    let in_reader = BufReader::new(stdin);
    let mut stdout = io::stdout();

    for line in in_reader.lines() {
        let translation = match line.as_ref().map(String::as_ref) {
                              Ok(text) => decode_line(text, include_ids, tag_per_line, color).to_string(),
                              Err(error) => error.to_string(),
                          };

        write!(stdout, "{}\n", translation).unwrap();
    }
}

fn enquote(text: &str) -> String {
    return if text == "" || text.contains(' ') { format!("'{}'", text) } else { text.to_string() };
}

fn decode_line(line: &str, include_ids: bool, tag_per_line: bool, color: bool) -> String {
    lazy_static! {
        static ref PATTERN: regex::Regex = regex::Regex::new(r"8=FIX\.\d+\.\d+\1.*?10=\d{3}\1").unwrap();
    }

    if !PATTERN.is_match(line) { return line.to_string(); }

    let mut translation = String::new();

    for field in line.split("\x01") {
        let pair: Vec<&str> = field.splitn(2, "=").collect();
        if pair.len() < 2 { continue; }

        let tag = pair[0];
        let value = pair[1];

        let decoded_tag = decode_tag(tag);
        let decoded_value = decode_value(tag, value);

        if include_ids
        {
            translation.push_str(&colorize(tag, &ansi::ANSI_RED, color));
            translation.push(':');
        }

        translation.push_str(&colorize(&decoded_tag, &ansi::ANSI_BRIGHT_WHITE, color));

        translation.push_str("=");

        if include_ids && value != decoded_value
        {
            translation.push_str(&colorize(value, &ansi::ANSI_YELLOW, color));
            translation.push(':');
        }

        translation.push_str(&enquote(&colorize_by_type(value, &decoded_value, color)));

        translation.push(if tag_per_line { '\n' } else {' '});
    }

    if tag_per_line
    {
        translation.push_str("-\n");
    }

    translation.pop();

    return translation;
}

fn colorize(text: &str, ansi_color_code: &str, use_color: bool) -> String {
    let mut result = String::new();

    if use_color { result.push_str(ansi_color_code); }
    result.push_str(text);
    if use_color { result.push_str(&ansi::ANSI_RESET); }

    return result;
}

fn colorize_by_type(value: &str, decoded: &str, use_color: bool) -> String {
    lazy_static! {
        static ref DATETIME_PATTERN: regex::Regex = regex::Regex::new(r"\d{8}-\d{2}:\d{2}:\d{2}(.\d{3})?").unwrap();
    }

    let is_decoded = decoded != value;
    let is_number = value.chars().all(|c| char::is_numeric(c) || c == '.');
    let is_date = DATETIME_PATTERN.is_match(value);

    let color_code = if is_decoded { ansi::ANSI_YELLOW }
                             else if is_number { ansi::ANSI_CYAN }
                             else if is_date { ansi::ANSI_MAGENTA }
                             else { ansi::ANSI_GREEN };

    return colorize(decoded, color_code, use_color);
}

fn decode_tag(tag: &str) -> String {
     let name = &dictionary::DICTIONARY["tags"][tag];

    return if !name.is_null() { name.to_string() } else { tag.to_string() };
}

fn decode_value<'a>(tag: &'a str, value: &'a str) -> String {
    let enumeration = &dictionary::DICTIONARY["enums"][tag];
    return if !enumeration.is_null() { enumeration[value].to_string() } else { value.to_string() };
}

fn die(message: &str) {
    println!("{}", message);
    process::exit(1);
}
<commit_msg>Remove forced build failure.y<commit_after>#[macro_use] extern crate lazy_static;
extern crate regex;
extern crate json;

use std::env;
use std::io;
use std::io::*;
use std::process;

mod dictionary;
mod ansi;

fn main() {
    let arguments: Vec<String> = env::args().collect();
    let action = env::args().nth(1);
    let include_ids = arguments.contains(&"--id".to_string());
    let tag_per_line = arguments.contains(&"--tag-per-line".to_string());
    let color = arguments.contains(&"--color".to_string());

    match action.as_ref().map(String::as_ref) {
        Some("decode") => process_stdin(include_ids, tag_per_line, color),
        Some(a) => die(&format!("unsupported action '{}'", &a)),
        None => die("Usage: transfix decode"),
    }
}

fn process_stdin(include_ids: bool, tag_per_line: bool, color: bool) {
    let stdin = io::stdin();
    let in_reader = BufReader::new(stdin);
    let mut stdout = io::stdout();

    for line in in_reader.lines() {
        let translation = match line.as_ref().map(String::as_ref) {
                              Ok(text) => decode_line(text, include_ids, tag_per_line, color).to_string(),
                              Err(error) => error.to_string(),
                          };

        write!(stdout, "{}\n", translation).unwrap();
    }
}

fn enquote(text: &str) -> String {
    return if text == "" || text.contains(' ') { format!("'{}'", text) } else { text.to_string() };
}

fn decode_line(line: &str, include_ids: bool, tag_per_line: bool, color: bool) -> String {
    lazy_static! {
        static ref PATTERN: regex::Regex = regex::Regex::new(r"8=FIX\.\d+\.\d+\1.*?10=\d{3}\1").unwrap();
    }

    if !PATTERN.is_match(line) { return line.to_string(); }

    let mut translation = String::new();

    for field in line.split("\x01") {
        let pair: Vec<&str> = field.splitn(2, "=").collect();
        if pair.len() < 2 { continue; }

        let tag = pair[0];
        let value = pair[1];

        let decoded_tag = decode_tag(tag);
        let decoded_value = decode_value(tag, value);

        if include_ids
        {
            translation.push_str(&colorize(tag, &ansi::ANSI_RED, color));
            translation.push(':');
        }

        translation.push_str(&colorize(&decoded_tag, &ansi::ANSI_BRIGHT_WHITE, color));

        translation.push_str("=");

        if include_ids && value != decoded_value
        {
            translation.push_str(&colorize(value, &ansi::ANSI_YELLOW, color));
            translation.push(':');
        }

        translation.push_str(&enquote(&colorize_by_type(value, &decoded_value, color)));

        translation.push(if tag_per_line { '\n' } else {' '});
    }

    if tag_per_line
    {
        translation.push_str("-\n");
    }

    translation.pop();

    return translation;
}

fn colorize(text: &str, ansi_color_code: &str, use_color: bool) -> String {
    let mut result = String::new();

    if use_color { result.push_str(ansi_color_code); }
    result.push_str(text);
    if use_color { result.push_str(&ansi::ANSI_RESET); }

    return result;
}

fn colorize_by_type(value: &str, decoded: &str, use_color: bool) -> String {
    lazy_static! {
        static ref DATETIME_PATTERN: regex::Regex = regex::Regex::new(r"\d{8}-\d{2}:\d{2}:\d{2}(.\d{3})?").unwrap();
    }

    let is_decoded = decoded != value;
    let is_number = value.chars().all(|c| char::is_numeric(c) || c == '.');
    let is_date = DATETIME_PATTERN.is_match(value);

    let color_code = if is_decoded { ansi::ANSI_YELLOW }
                             else if is_number { ansi::ANSI_CYAN }
                             else if is_date { ansi::ANSI_MAGENTA }
                             else { ansi::ANSI_GREEN };

    return colorize(decoded, color_code, use_color);
}

fn decode_tag(tag: &str) -> String {
     let name = &dictionary::DICTIONARY["tags"][tag];

    return if !name.is_null() { name.to_string() } else { tag.to_string() };
}

fn decode_value<'a>(tag: &'a str, value: &'a str) -> String {
    let enumeration = &dictionary::DICTIONARY["enums"][tag];
    return if !enumeration.is_null() { enumeration[value].to_string() } else { value.to_string() };
}

fn die(message: &str) {
    println!("{}", message);
    process::exit(1);
}
<|endoftext|>


<commit_before>extern crate rand;

use std::string::String;
use std::collections::HashMap;
use std::vec::Vec;
use std::fs::{File};
use std::env;
use std::path::{Path};
use std::io::{self, BufReader, BufRead};
use std::iter;

use rand::{Closed01, Rng};
use rand::distributions::{IndependentSample, Sample, Gamma, LogNormal, RandSample};

type Bag = HashMap<usize, usize>;

fn load_bags<P: AsRef<Path>>(path: P) -> io::Result<(Vec<usize>, Vec<Bag>)> {
    let mut bags = Vec::new();
    let mut labels = Vec::new();
    let file = try!(File::open(path));
    let file = BufReader::new(file);
    for line in file.lines() {
        let line = line.unwrap();
        let mut iter = line.split_whitespace();
        let label = iter.next().unwrap().parse::<usize>().unwrap();
        let mut bag = Bag::new();
        for elm in iter {
            let mut iter = elm.split(':');
            let index = iter.next().unwrap().parse::<usize>().unwrap();
            let value = iter.next().unwrap().parse::<usize>().unwrap();
            bag.insert(index - 1, value);
        }
        labels.push(label);
        bags.push(bag);
    }
    Ok((labels, bags))
}

fn load_text_vocabulary<P: AsRef<Path>>(path: P) -> io::Result<Vec<String>> {
    let mut vocab = Vec::new();
    let file = try!(File::open(path));
    let file = BufReader::new(file);
    for line in file.lines() {
        let line = line.unwrap();
        vocab.push(line);
    }
    Ok(vocab)
}

#[derive(Clone)]
struct Categorical {
    prop: Vec<f64>,
}

impl Categorical {
    fn new(weights: Vec<f64>) -> Categorical {
        let sum: f64 = weights.iter().sum();
        let prop: Vec<f64> = weights.iter().map(|w| w / sum).collect();
        Categorical {
            prop: prop,
        }
    }
}

impl Sample<usize> for Categorical {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> usize {
        self.ind_sample(rng)
    }
}

impl IndependentSample<usize> for Categorical {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> usize {
        let closed01 = RandSample::<Closed01<f64>>::new();
        let Closed01(x) = closed01.ind_sample(rng);

        let mut sum = 0.0;
        let mut ret = self.prop.len() - 1;
        for (k, &p) in self.prop.iter().enumerate() {
            sum += p;
            if x <= sum {
                ret = k;
                break;
            }
        }
        ret
    }
}

#[derive(Clone)]
struct Dirichlet {
    alpha: Vec<f64>,
}

impl Dirichlet {
    fn new(alpha: Vec<f64>) -> Dirichlet {
        Dirichlet {
            alpha: alpha,
        }
    }
}

impl Sample<Vec<f64>> for Dirichlet {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Vec<f64> {
        self.ind_sample(rng)
    }
}

impl IndependentSample<Vec<f64>> for Dirichlet {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Vec<f64> {
        let mut sum = 0.0;
        let mut xs = Vec::new();
        for &a in &self.alpha {
            let gamma = Gamma::new(a, 1.0);
            let y = gamma.ind_sample(rng);
            xs.push(y);
            sum += y;
        }
        for x in xs.iter_mut() {
            *x /= sum;
        }
        xs
    }
}

fn lda(dataset: Vec<Bag>, num_topics: usize, alpha: Vec<f64>, beta: Vec<f64>, burn_in: usize, num_samples: usize) {
    // Initialization
    let vocab_size: usize = {
        let mut have_some = false;
        let mut max_index = 0;
        for bag in &dataset {
            for &index in bag.keys() {
                have_some = true;
                if index > max_index {
                    max_index = index;
                }
            }
        }
        if have_some {
            max_index + 1
        }
        else {
            0
        }
    };
    println!("K = {}", num_topics);
    println!("M = {}", &dataset.len());
    println!("V = {}", vocab_size);

    let mut w: Vec<Vec<usize>> = Vec::new();
    let mut z: Vec<Vec<usize>> = Vec::new();
    let mut z_samples: Vec<Vec<Vec<usize>>> = Vec::new();
    let mut theta: Vec<Vec<f64>> = Vec::new();
    let mut ndk: Vec<Vec<usize>> = Vec::new();
    for bag in &dataset {
        // w
        let mut w_d = Vec::new();
        for (&index, &count) in bag {
            for _ in 0..count {
                w_d.push(index);
            }
        }
        w.push(w_d);
        // z
        let mut z_d = Vec::new();
        let mut z_samples_d = Vec::new();
        for &count in bag.values() {
            for _ in 0..count {
                z_d.push(0);
                let zeros: Vec<usize> = iter::repeat(0).take(num_topics).collect();
                z_samples_d.push(zeros);
            }
        }
        let n_d = z_d.len();
        z.push(z_d);
        z_samples.push(z_samples_d);
        // theta
        let mut theta_d = Vec::with_capacity(num_topics);
        for _k in 0..num_topics {
            theta_d.push(1.0 / num_topics as f64);
        }
        theta.push(theta_d);
        // ndk
        let mut ndk_d = Vec::with_capacity(num_topics);
        ndk_d.push(n_d);
        for _k in 1..num_topics {
            ndk_d.push(0);
        }
        ndk.push(ndk_d);
    }
    println!("z = {:?}", z);
    println!("theta = {:?}", theta);
    println!("ndk = {:?}", ndk);

    let mut phi: Vec<Vec<f64>> = Vec::new();
    let mut nkv: Vec<Vec<usize>> = Vec::new();
    // phi
    for _k in 0..num_topics {
        let mut phi_k = Vec::new();
        for _v in 0..vocab_size {
            phi_k.push(1.0 / vocab_size as f64);
        }
        phi.push(phi_k);
    }
    // nkv
    let mut nkv_0 = Vec::new();
    for _v in 0..vocab_size {
        nkv_0.push(0);
    }
    for bag in &dataset {
        for (&index, &count) in bag {
            nkv_0[index] += count;
        }
    }
    nkv.push(nkv_0);
    for _k in 1..num_topics {
        let mut nkv_k = Vec::new();
        for _v in 0..vocab_size {
            nkv_k.push(0);
        }
        nkv.push(nkv_k);
    }
    println!("phi = {:?}", phi);
    println!("nkv = {:?}", nkv);

    // Sampling
    let mut rng = rand::thread_rng();
    for s in 0..(burn_in + num_samples) {
        for (d, w_d) in w.iter().enumerate() {
            for (i, &w_di) in w_d.iter().enumerate() {
                let v = w_di;
                // Sample z_di
                let mut weights: Vec<f64> = Vec::new();
                for k in 0..num_topics {
                    weights.push(theta[d][k] * phi[k][v]);
                }
                let cat = Categorical::new(weights);
                let old_z_di = z[d][i];
                let new_z_di = cat.ind_sample(&mut rng);
                z[d][i] = new_z_di;
                if s >= burn_in {
                    z_samples[d][i][new_z_di] += 1;
                }
                // Update ndk and nkv
                ndk[d][old_z_di] -= 1;
                ndk[d][new_z_di] += 1;
                nkv[old_z_di][v] -= 1;
                nkv[new_z_di][v] += 1;
            }
            // Sample theta_d
            let mut alpha_d: Vec<f64> = Vec::new();
            for k in 0..num_topics {
                alpha_d.push(ndk[d][k] as f64 + alpha[k]);
            }
            let dir = Dirichlet::new(alpha_d);
            theta[d] = dir.ind_sample(&mut rng);
        }
        for k in 0..num_topics {
            // Sample phi_k
            let mut beta_k: Vec<f64> = Vec::new();
            for v in 0..vocab_size {
                beta_k.push(nkv[k][v] as f64 + beta[v]);
            }
            let dir = Dirichlet::new(beta_k);
            phi[k] = dir.ind_sample(&mut rng);
        }
        // Evaluate the log-likelihood value for the current parameters
        let mut log_likelihood = 0.0;
        for k in 0..num_topics {
            for v in 0..vocab_size {
                log_likelihood += nkv[k][v] as f64 * f64::ln(phi[k][v]);
            }
        }
        println!("log_likelihood = {}", log_likelihood);
    }
    for (d, z_samples_d) in z_samples.iter().enumerate() {
        for (i, samples) in z_samples_d.iter().enumerate() {
            let mut sum = 0.0;
            for k in 0..num_topics {
                sum += samples[k] as f64;
            }
            print!("z[{:3}][{:3}] = ", d, i);
            for k in 0..num_topics {
                print!("{:3}:{:.2} ", k, samples[k] as f64 / sum);
            }
            println!("");
        }
    }
}

fn make_dataset(num_docs: usize, vocab_size: usize, num_topics: usize, alpha: Vec<f64>, beta: Vec<f64>) -> Vec<Bag> {
    let mut rng = rand::thread_rng();
    // phi
    let dir_beta = Dirichlet::new(beta);
    let mut phi: Vec<Vec<f64>> = Vec::with_capacity(num_topics);
    for k in 0..num_topics {
        // Sample phi_k
        phi.push(dir_beta.ind_sample(&mut rng));
    }
    // theta, nd, z, w
    let dir_alpha = Dirichlet::new(alpha);
    let lognorm = LogNormal::new(100.0, 30.0);
    let mut theta: Vec<Vec<f64>> = Vec::with_capacity(num_docs);
    let mut nd: Vec<usize> = Vec::with_capacity(num_docs);
    let mut z: Vec<Vec<usize>> = Vec::with_capacity(num_docs);
    let mut w: Vec<Vec<usize>> = Vec::with_capacity(num_docs);
    for d in 0..num_docs {
        theta.push(dir_alpha.ind_sample(&mut rng));
        nd.push(f64::floor(lognorm.ind_sample(&mut rng)) as usize);
        let cat_theta = Categorical::new(theta[d].clone());
        let mut z_d = Vec::with_capacity(nd[d]);
        let mut w_d = Vec::with_capacity(nd[d]);
        for i in 0..nd[d] {
            z_d.push(cat_theta.ind_sample(&mut rng));
            let cat_phi = Categorical::new(phi[z_d[i]].clone());
            w_d.push(cat_phi.ind_sample(&mut rng));
        }
        z.push(z_d);
        w.push(w_d);
    }
    // Make bags
    let mut bags: Vec<Bag> = Vec::new();
    for w_d in w {
        let mut bag: Bag = Bag::new();
        for v in w_d {
            let counter = bag.entry(v).or_insert(0);
            *counter += 1;
        }
        bags.push(bag);
    }
    bags
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let (labels, dataset) = load_bags(&args[1]).unwrap();
    let vocab: Option<Vec<String>> = if args.len() < 3 {
        None
    }
    else {
        Some(load_text_vocabulary(&args[2]).unwrap())
    };
    println!("{:?}", labels);
    println!("{:?}", dataset);
    println!("{:?}", vocab);

    let num_topics = 3;
    let alpha: Vec<f64> = iter::repeat(1.0).take(num_topics).collect();
    let beta: Vec<f64> = iter::repeat(1.0).take(vocab.unwrap().len()).collect();

    lda(dataset, num_topics, alpha, beta, 1000, 10000);
}
<commit_msg>load_bags() now also returns the size of vocabulary used<commit_after>extern crate rand;

use std::string::String;
use std::collections::HashMap;
use std::vec::Vec;
use std::fs::{File};
use std::env;
use std::path::{Path};
use std::io::{self, BufReader, BufRead};
use std::iter;

use rand::{Closed01, Rng};
use rand::distributions::{IndependentSample, Sample, Gamma, LogNormal, RandSample};

type Bag = HashMap<usize, usize>;

fn load_bags<P: AsRef<Path>>(path: P) -> io::Result<(Vec<usize>, Vec<Bag>, usize)> {
    let mut bags = Vec::new();
    let mut labels = Vec::new();
    let mut vocab_size = 0;
    let file = try!(File::open(path));
    let file = BufReader::new(file);
    for line in file.lines() {
        let line = line.unwrap();
        let mut iter = line.split_whitespace();
        let label = iter.next().unwrap().parse::<usize>().unwrap();
        let mut bag = Bag::new();
        for elm in iter {
            let mut iter = elm.split(':');
            let index = iter.next().unwrap().parse::<usize>().unwrap();
            let value = iter.next().unwrap().parse::<usize>().unwrap();
            bag.insert(index - 1, value);    // We assume one-based indexing
            if vocab_size < index {
                vocab_size = index;
            }
        }
        labels.push(label);
        bags.push(bag);
    }
    Ok((labels, bags, vocab_size))
}

fn load_text_vocabulary<P: AsRef<Path>>(path: P) -> io::Result<Vec<String>> {
    let mut vocab = Vec::new();
    let file = try!(File::open(path));
    let file = BufReader::new(file);
    for line in file.lines() {
        let line = line.unwrap();
        vocab.push(line);
    }
    Ok(vocab)
}

#[derive(Clone)]
struct Categorical {
    prop: Vec<f64>,
}

impl Categorical {
    fn new(weights: Vec<f64>) -> Categorical {
        let sum: f64 = weights.iter().sum();
        let prop: Vec<f64> = weights.iter().map(|w| w / sum).collect();
        Categorical {
            prop: prop,
        }
    }
}

impl Sample<usize> for Categorical {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> usize {
        self.ind_sample(rng)
    }
}

impl IndependentSample<usize> for Categorical {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> usize {
        let closed01 = RandSample::<Closed01<f64>>::new();
        let Closed01(x) = closed01.ind_sample(rng);

        let mut sum = 0.0;
        let mut ret = self.prop.len() - 1;
        for (k, &p) in self.prop.iter().enumerate() {
            sum += p;
            if x <= sum {
                ret = k;
                break;
            }
        }
        ret
    }
}

#[derive(Clone)]
struct Dirichlet {
    alpha: Vec<f64>,
}

impl Dirichlet {
    fn new(alpha: Vec<f64>) -> Dirichlet {
        Dirichlet {
            alpha: alpha,
        }
    }
}

impl Sample<Vec<f64>> for Dirichlet {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Vec<f64> {
        self.ind_sample(rng)
    }
}

impl IndependentSample<Vec<f64>> for Dirichlet {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Vec<f64> {
        let mut sum = 0.0;
        let mut xs = Vec::new();
        for &a in &self.alpha {
            let gamma = Gamma::new(a, 1.0);
            let y = gamma.ind_sample(rng);
            xs.push(y);
            sum += y;
        }
        for x in xs.iter_mut() {
            *x /= sum;
        }
        xs
    }
}

fn lda(dataset: Vec<Bag>, num_topics: usize, alpha: Vec<f64>, beta: Vec<f64>, burn_in: usize, num_samples: usize) {
    // Initialization
    let vocab_size: usize = {
        let mut have_some = false;
        let mut max_index = 0;
        for bag in &dataset {
            for &index in bag.keys() {
                have_some = true;
                if index > max_index {
                    max_index = index;
                }
            }
        }
        if have_some {
            max_index + 1
        }
        else {
            0
        }
    };
    println!("K = {}", num_topics);
    println!("M = {}", &dataset.len());
    println!("V = {}", vocab_size);

    let mut w: Vec<Vec<usize>> = Vec::new();
    let mut z: Vec<Vec<usize>> = Vec::new();
    let mut z_samples: Vec<Vec<Vec<usize>>> = Vec::new();
    let mut theta: Vec<Vec<f64>> = Vec::new();
    let mut ndk: Vec<Vec<usize>> = Vec::new();
    for bag in &dataset {
        // w
        let mut w_d = Vec::new();
        for (&index, &count) in bag {
            for _ in 0..count {
                w_d.push(index);
            }
        }
        w.push(w_d);
        // z
        let mut z_d = Vec::new();
        let mut z_samples_d = Vec::new();
        for &count in bag.values() {
            for _ in 0..count {
                z_d.push(0);
                let zeros: Vec<usize> = iter::repeat(0).take(num_topics).collect();
                z_samples_d.push(zeros);
            }
        }
        let n_d = z_d.len();
        z.push(z_d);
        z_samples.push(z_samples_d);
        // theta
        let mut theta_d = Vec::with_capacity(num_topics);
        for _k in 0..num_topics {
            theta_d.push(1.0 / num_topics as f64);
        }
        theta.push(theta_d);
        // ndk
        let mut ndk_d = Vec::with_capacity(num_topics);
        ndk_d.push(n_d);
        for _k in 1..num_topics {
            ndk_d.push(0);
        }
        ndk.push(ndk_d);
    }
    println!("z = {:?}", z);
    println!("theta = {:?}", theta);
    println!("ndk = {:?}", ndk);

    let mut phi: Vec<Vec<f64>> = Vec::new();
    let mut nkv: Vec<Vec<usize>> = Vec::new();
    // phi
    for _k in 0..num_topics {
        let mut phi_k = Vec::new();
        for _v in 0..vocab_size {
            phi_k.push(1.0 / vocab_size as f64);
        }
        phi.push(phi_k);
    }
    // nkv
    let mut nkv_0 = Vec::new();
    for _v in 0..vocab_size {
        nkv_0.push(0);
    }
    for bag in &dataset {
        for (&index, &count) in bag {
            nkv_0[index] += count;
        }
    }
    nkv.push(nkv_0);
    for _k in 1..num_topics {
        let mut nkv_k = Vec::new();
        for _v in 0..vocab_size {
            nkv_k.push(0);
        }
        nkv.push(nkv_k);
    }
    println!("phi = {:?}", phi);
    println!("nkv = {:?}", nkv);

    // Sampling
    let mut rng = rand::thread_rng();
    for s in 0..(burn_in + num_samples) {
        for (d, w_d) in w.iter().enumerate() {
            for (i, &w_di) in w_d.iter().enumerate() {
                let v = w_di;
                // Sample z_di
                let mut weights: Vec<f64> = Vec::new();
                for k in 0..num_topics {
                    weights.push(theta[d][k] * phi[k][v]);
                }
                let cat = Categorical::new(weights);
                let old_z_di = z[d][i];
                let new_z_di = cat.ind_sample(&mut rng);
                z[d][i] = new_z_di;
                if s >= burn_in {
                    z_samples[d][i][new_z_di] += 1;
                }
                // Update ndk and nkv
                ndk[d][old_z_di] -= 1;
                ndk[d][new_z_di] += 1;
                nkv[old_z_di][v] -= 1;
                nkv[new_z_di][v] += 1;
            }
            // Sample theta_d
            let mut alpha_d: Vec<f64> = Vec::new();
            for k in 0..num_topics {
                alpha_d.push(ndk[d][k] as f64 + alpha[k]);
            }
            let dir = Dirichlet::new(alpha_d);
            theta[d] = dir.ind_sample(&mut rng);
        }
        for k in 0..num_topics {
            // Sample phi_k
            let mut beta_k: Vec<f64> = Vec::new();
            for v in 0..vocab_size {
                beta_k.push(nkv[k][v] as f64 + beta[v]);
            }
            let dir = Dirichlet::new(beta_k);
            phi[k] = dir.ind_sample(&mut rng);
        }
        // Evaluate the log-likelihood value for the current parameters
        let mut log_likelihood = 0.0;
        for k in 0..num_topics {
            for v in 0..vocab_size {
                log_likelihood += nkv[k][v] as f64 * f64::ln(phi[k][v]);
            }
        }
        println!("log_likelihood = {}", log_likelihood);
    }
    for (d, z_samples_d) in z_samples.iter().enumerate() {
        for (i, samples) in z_samples_d.iter().enumerate() {
            let mut sum = 0.0;
            for k in 0..num_topics {
                sum += samples[k] as f64;
            }
            print!("z[{:3}][{:3}] = ", d, i);
            for k in 0..num_topics {
                print!("{:3}:{:.2} ", k, samples[k] as f64 / sum);
            }
            println!("");
        }
    }
}

fn make_dataset(num_docs: usize, vocab_size: usize, num_topics: usize, alpha: Vec<f64>, beta: Vec<f64>) -> Vec<Bag> {
    let mut rng = rand::thread_rng();
    // phi
    let dir_beta = Dirichlet::new(beta);
    let mut phi: Vec<Vec<f64>> = Vec::with_capacity(num_topics);
    for k in 0..num_topics {
        // Sample phi_k
        phi.push(dir_beta.ind_sample(&mut rng));
    }
    // theta, nd, z, w
    let dir_alpha = Dirichlet::new(alpha);
    let lognorm = LogNormal::new(100.0, 30.0);
    let mut theta: Vec<Vec<f64>> = Vec::with_capacity(num_docs);
    let mut nd: Vec<usize> = Vec::with_capacity(num_docs);
    let mut z: Vec<Vec<usize>> = Vec::with_capacity(num_docs);
    let mut w: Vec<Vec<usize>> = Vec::with_capacity(num_docs);
    for d in 0..num_docs {
        theta.push(dir_alpha.ind_sample(&mut rng));
        nd.push(f64::floor(lognorm.ind_sample(&mut rng)) as usize);
        let cat_theta = Categorical::new(theta[d].clone());
        let mut z_d = Vec::with_capacity(nd[d]);
        let mut w_d = Vec::with_capacity(nd[d]);
        for i in 0..nd[d] {
            z_d.push(cat_theta.ind_sample(&mut rng));
            let cat_phi = Categorical::new(phi[z_d[i]].clone());
            w_d.push(cat_phi.ind_sample(&mut rng));
        }
        z.push(z_d);
        w.push(w_d);
    }
    // Make bags
    let mut bags: Vec<Bag> = Vec::new();
    for w_d in w {
        let mut bag: Bag = Bag::new();
        for v in w_d {
            let counter = bag.entry(v).or_insert(0);
            *counter += 1;
        }
        bags.push(bag);
    }
    bags
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let (labels, dataset, vocab_size) = load_bags(&args[1]).unwrap();
    let vocab: Option<Vec<String>> = if args.len() < 3 {
        None
    }
    else {
        Some(load_text_vocabulary(&args[2]).unwrap())
    };
    println!("{:?}", labels);
    println!("{:?}", dataset);
    println!("{:?}", vocab);

    let num_topics = 3;
    let alpha: Vec<f64> = iter::repeat(1.0).take(num_topics).collect();
    let beta: Vec<f64> = iter::repeat(1.0).take(vocab_size).collect();

    lda(dataset, num_topics, alpha, beta, 1000, 10000);
}
<|endoftext|>


<commit_before>// This is so cargo actually considers linking to the fucking manifest,
// since the build scripts' documentation can do the digital equivalent of fucking off
#[cfg(target_os="windows")]
#[link(name="cargo-install-update-manifest", kind="static")]
extern "C" {}

extern crate cargo_update;
extern crate tabwriter;
extern crate regex;

use std::process::{Command, exit};
use std::io::{Write, stdout};
use std::fs::{self, File};
use tabwriter::TabWriter;
use regex::Regex;
use std::env;

fn main() {
    let result = actual_main().err().unwrap_or(0);
    exit(result);
}

fn actual_main() -> Result<(), i32> {
    let opts = cargo_update::Options::parse();

    if cfg!(target_os = "windows") {
        let old_version_r = Regex::new(r"cargo-install-update\.exe-v.+").unwrap();
        for old_version in fs::read_dir(env::current_exe().unwrap().parent().unwrap().canonicalize().unwrap())
            .unwrap()
            .map(Result::unwrap)
            .filter(|f| old_version_r.is_match(&f.file_name().into_string().unwrap())) {
            fs::remove_file(old_version.path()).unwrap();
        }
    }

    let mut packages = cargo_update::ops::installed_main_repo_packages(&opts.cargo_dir.1);

    if !opts.to_update.is_empty() {
        packages = cargo_update::ops::intersect_packages(packages, &opts.to_update);
    }

    {
        // Searching for "" will just update the registry
        let search_res = Command::new("cargo").arg("search").arg("").status().unwrap();
        if !search_res.success() {
            try!(Err(search_res.code().unwrap_or(-1)));
        }
        println!("");
    }

    let registry = cargo_update::ops::get_index_path(&opts.cargo_dir.1);

    for package in &mut packages {
        package.pull_version(&registry);
    }

    {
        let mut out = TabWriter::new(stdout());
        writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
        for package in &packages {
            writeln!(out,
                     "{}\tv{}\tv{}\t{}",
                     package.name,
                     package.version,
                     package.newest_version.as_ref().unwrap(),
                     if package.version < *package.newest_version.as_ref().unwrap() {
                         "Yes"
                     } else {
                         "No"
                     })
                .unwrap();
        }
        writeln!(out, "").unwrap();
        out.flush().unwrap();
    }

    if opts.update {
        if !opts.force {
            packages = packages.into_iter().filter(|pkg| pkg.version < *pkg.newest_version.as_ref().unwrap()).collect();
        }

        if !packages.is_empty() {
            let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                .map(|package| -> Result<(), (i32, String)> {
                    println!("Updating {}", package.name);

                    if cfg!(target_os = "windows") && package.name == "cargo-update" {
                        let cur_exe = env::current_exe().unwrap();
                        let mut new_exe = cur_exe.clone();

                        new_exe.set_extension(format!("exe-v{}", package.version));
                        fs::rename(&cur_exe, new_exe).unwrap();
                        // This way the past-current exec will be "replaced" we'll get no dupes in .cargo.toml
                        File::create(cur_exe).unwrap();
                    }

                    let install_res = Command::new("cargo").arg("install").arg("-f").arg(&package.name).status().unwrap();
                    if !install_res.success() {
                        try!(Err((install_res.code().unwrap_or(-1), package.name)));
                    }

                    println!("");

                    Ok(())
                })
                .collect::<Vec<_>>()
                .into_iter()
                .fold((0, vec![], None), |(s, mut e, r), p| match p {
                    Ok(()) => (s + 1, e, r),
                    Err((pr, pn)) => {
                        e.push(pn);
                        (s, e, r.or(Some(pr)))
                    }
                });

            println!("");
            println!("Updated {} package{}.", success_n, if success_n == 1 { "" } else { "s" });
            if !errored.is_empty() && result.is_some() {
                println!("Failed to update {}.", &errored.iter().fold("".to_string(), |s, e| s + ", " + e)[2..]);
                try!(Err(result.unwrap()));
            }
        } else {
            println!("No packages need updating.");
        }
    }

    Ok(())
}
<commit_msg>Don't collect(), which is not unnecessary, so performance goes through the roof now<commit_after>// This is so cargo actually considers linking to the fucking manifest,
// since the build scripts' documentation can do the digital equivalent of fucking off
#[cfg(target_os="windows")]
#[link(name="cargo-install-update-manifest", kind="static")]
extern "C" {}

extern crate cargo_update;
extern crate tabwriter;
extern crate regex;

use std::process::{Command, exit};
use std::io::{Write, stdout};
use std::fs::{self, File};
use tabwriter::TabWriter;
use regex::Regex;
use std::env;

fn main() {
    let result = actual_main().err().unwrap_or(0);
    exit(result);
}

fn actual_main() -> Result<(), i32> {
    let opts = cargo_update::Options::parse();

    if cfg!(target_os = "windows") {
        let old_version_r = Regex::new(r"cargo-install-update\.exe-v.+").unwrap();
        for old_version in fs::read_dir(env::current_exe().unwrap().parent().unwrap().canonicalize().unwrap())
            .unwrap()
            .map(Result::unwrap)
            .filter(|f| old_version_r.is_match(&f.file_name().into_string().unwrap())) {
            fs::remove_file(old_version.path()).unwrap();
        }
    }

    let mut packages = cargo_update::ops::installed_main_repo_packages(&opts.cargo_dir.1);

    if !opts.to_update.is_empty() {
        packages = cargo_update::ops::intersect_packages(packages, &opts.to_update);
    }

    {
        // Searching for "" will just update the registry
        let search_res = Command::new("cargo").arg("search").arg("").status().unwrap();
        if !search_res.success() {
            try!(Err(search_res.code().unwrap_or(-1)));
        }
        println!("");
    }

    let registry = cargo_update::ops::get_index_path(&opts.cargo_dir.1);

    for package in &mut packages {
        package.pull_version(&registry);
    }

    {
        let mut out = TabWriter::new(stdout());
        writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
        for package in &packages {
            writeln!(out,
                     "{}\tv{}\tv{}\t{}",
                     package.name,
                     package.version,
                     package.newest_version.as_ref().unwrap(),
                     if package.version < *package.newest_version.as_ref().unwrap() {
                         "Yes"
                     } else {
                         "No"
                     })
                .unwrap();
        }
        writeln!(out, "").unwrap();
        out.flush().unwrap();
    }

    if opts.update {
        if !opts.force {
            packages = packages.into_iter().filter(|pkg| pkg.version < *pkg.newest_version.as_ref().unwrap()).collect();
        }

        if !packages.is_empty() {
            let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                .map(|package| -> Result<(), (i32, String)> {
                    println!("Updating {}", package.name);

                    if cfg!(target_os = "windows") && package.name == "cargo-update" {
                        let cur_exe = env::current_exe().unwrap();
                        let mut new_exe = cur_exe.clone();

                        new_exe.set_extension(format!("exe-v{}", package.version));
                        fs::rename(&cur_exe, new_exe).unwrap();
                        // This way the past-current exec will be "replaced" we'll get no dupes in .cargo.toml
                        File::create(cur_exe).unwrap();
                    }

                    let install_res = Command::new("cargo").arg("install").arg("-f").arg(&package.name).status().unwrap();
                    if !install_res.success() {
                        try!(Err((install_res.code().unwrap_or(-1), package.name)));
                    }

                    println!("");

                    Ok(())
                })
                .fold((0, vec![], None), |(s, mut e, r), p| match p {
                    Ok(()) => (s + 1, e, r),
                    Err((pr, pn)) => {
                        e.push(pn);
                        (s, e, r.or(Some(pr)))
                    }
                });

            println!("");
            println!("Updated {} package{}.", success_n, if success_n == 1 { "" } else { "s" });
            if !errored.is_empty() && result.is_some() {
                println!("Failed to update {}.", &errored.iter().fold("".to_string(), |s, e| s + ", " + e)[2..]);
                try!(Err(result.unwrap()));
            }
        } else {
            println!("No packages need updating.");
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate bmp;
extern crate num;

use num::complex::*;
use bmp::{Image, Pixel};

const SIZE: u32 = 512;
const ESCAPE_LIMIT: f64 = 1000000.0;
const ITER_LIMIT: u32 = 200;
const WIDTH: f64 = 3.0;
const HEIGHT: f64 = 3.0;
const C_VAL: Complex64 = Complex{re: 0.25, im: 0.5};

// Mendelbrot transform
fn fractal_func(c: Complex64) -> Box<Fn(Complex64) -> Complex64>
{
    return Box::new(move |z: Complex64| z.powf(2.0) + c);
}

fn run_until_escape(z: Complex64, escape_limit: f64, iter_limit: u32,
                    gen_fn: Box<Fn(Complex64) -> Complex64>) -> u32
{
    let mut temp = z;
    let mut n: u32 = 0;
    while temp.norm_sqr() < escape_limit && n < iter_limit {
        n += 1;
        temp = (*gen_fn)(temp);
    }

    return n;
}

fn main() {
    let mut pixels = vec![0; (SIZE*SIZE) as usize];

    let coordinates: Vec<(u32, u32)> = (0..SIZE).flat_map(move |x| (0..SIZE).map(move |y| (x,y))).collect();
    for &(x, y) in &coordinates {
        let float_x: f64 = WIDTH*((x as f64)/(SIZE as f64) - 0.5);
        let float_y: f64 = HEIGHT*((y as f64)/(SIZE as f64) - 0.5);
        let iterations = run_until_escape(Complex{re:float_x, im:float_y},
                                          ESCAPE_LIMIT, ITER_LIMIT,
                                          fractal_func(C_VAL));
        pixels[(SIZE*x + y) as usize] = iterations;
    }

    let max = pixels.iter().cloned().filter(|&x| x < ITER_LIMIT).max().unwrap();
    println!("max pixel: {}", max);

    for &(x, y) in &coordinates {
            let current = pixels[(SIZE*x + y) as usize];
            if current < ITER_LIMIT {
                pixels[(SIZE*x + y) as usize] *= 256;
                pixels[(SIZE*x + y) as usize] /= max;
            }
            else {
                pixels[(SIZE*x + y) as usize] = 256;
            }
    }

    let mut img = Image::new(SIZE, SIZE);
    for (x,y) in img.coordinates()
    {
        let val = pixels[(SIZE*x + y) as usize];
        img.set_pixel(x, y, px!(val, val, val));
    }

    let _ = img.save("test.bmp");
}
<commit_msg>Added burning ship fractal<commit_after>#[macro_use]
extern crate bmp;
extern crate num;

use num::complex::*;
use bmp::{Image, Pixel};

const SIZE: u32 = 256;
const ESCAPE_LIMIT: f64 = 1000000.0;
const ITER_LIMIT: u32 = 200;
const WIDTH: f64 = 0.005;
const HEIGHT: f64 = 0.010;
const X_CENTER: f64 = 1.941;
const Y_CENTER: f64 = 0.004;

// Burning ship
#[inline]
fn burning_ship() -> Box<Fn(Complex64, Complex64) -> Complex64>
{
    return Box::new(move |z: Complex64, c: Complex64| (Complex{re: z.re.abs(), im: z.im.abs()}).powf(2.0) + c);
}

// Mendelbrot
fn mandelbrot() -> Box<Fn(Complex64, Complex64) -> Complex64>
{
    return Box::new(move |z: Complex64, c: Complex64| z.powf(2.0) + c);
}

fn run_until_escape(gen_fn: Box<Fn(Complex64, Complex64) -> Complex64>,
    c: Complex64, escape_limit: f64, iter_limit: u32) -> u32
{
    let mut z: Complex64 = Complex64{ re: 0.0, im: 0.0};
    let mut n: u32 = 0;
    while z.norm_sqr() < escape_limit && n < iter_limit {
        n += 1;
        z = (*gen_fn)(z, c);
    }

    return n;
}

fn main() {
    let mut pixels = vec![0; (SIZE*SIZE) as usize];

    let coordinates: Vec<(u32, u32)> = (0..SIZE).flat_map(move |x| (0..SIZE).map(move |y| (x,y))).collect();
    for &(x, y) in &coordinates {
        let float_x: f64 = WIDTH*((x as f64)/(SIZE as f64) - 0.5) - X_CENTER;
        let float_y: f64 = HEIGHT*((y as f64)/(SIZE as f64) - 0.5) - Y_CENTER;
        let iterations = run_until_escape(burning_ship(), Complex{re: float_x, im: float_y},
                                          ESCAPE_LIMIT, ITER_LIMIT);
        pixels[(SIZE*x + y) as usize] = iterations;
    }

    let max = pixels.iter().cloned().filter(|&x| x < ITER_LIMIT).max().unwrap();
    println!("max pixel: {}", max);

    for &(x, y) in &coordinates {
            let current = pixels[(SIZE*x + y) as usize];
            if current < ITER_LIMIT {
                pixels[(SIZE*x + y) as usize] *= 256;
                pixels[(SIZE*x + y) as usize] /= max;
            }
            else {
                pixels[(SIZE*x + y) as usize] = 256;
            }
    }

    let mut img = Image::new(SIZE, SIZE);
    for (x,y) in img.coordinates()
    {
        let val = pixels[(SIZE*x + y) as usize];
        img.set_pixel(x, y, px!(val, val, val));
    }

    let _ = img.save("test.bmp");
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::iter::repeat;
use std::str::FromStr;

enum Hamming { Encode, Decode }

fn main() {
    let title = "RUSTYHAM: A HAMMING CODE GENERATOR IN RUST";
    let border: String = repeat('=').take(title.len()).collect::<>();
    println!("{}", border);
    println!("{}", title);
    println!("{}", border);

    loop {
        let mut linebuf = String::new();
        println!("(1) Encode ASCII");
        println!("*(2) Encode binary");
        println!("(3) Decode to ASCII");
        println!("*(4) Decode to binary");
        println!("Note: options marked as * are not supported yet.");
        print!("Enter your choice: ");
        io::stdout().flush().unwrap();
        io::stdin().read_line(&mut linebuf).unwrap();

        let num = i32::from_str(linebuf.trim());
        match num.ok() {
            Some(n) => {
                let mut good = true;
                println!("{}", match n {
                    1 => hamming(Hamming::Encode),
                    3 => hamming(Hamming::Decode),
                    2 | 4 => "Sorry, not implemented yet.".to_string(),
                    _ => { good = false; "Invalid input.".to_string() }
                });
                if good { break; }
            }
            None => {
                println!("Invalid input.");
            }
        };
    }
}

fn hamming(action: Hamming) -> String {
    match action {
        Hamming::Encode => {
            // prompt for ASCII input
            let message = prompt("Enter string to encode: ");

            // compute block and message length
            let mlen = message.len() as u32 * 7;
            let lenpow = (2..).find(|&r| 2u32.pow(r) - r - 1 >= mlen).unwrap();
            let len = 2us.pow(lenpow) - 1;

            // the thing we're storing the hamming code in
            let mut code: Vec<bool> = repeat(false).take(len).collect::<>();

            // convert ASCII string to binary
            // IMPORTANT NOTE: the following line takes ownership of the
            // `message' variable. We no longer have access to the original
            // string from this point onwards.
            let bytes = message.into_bytes();
            let bytes_str = bytes.iter().map(|&c| format!("{:0>1$b}", c, 7))
                .collect::<Vec<String>>().concat();

            // set data bits
            let mut bytes_iter = bytes_str.chars();
            for i in 1..len {
                if (i & (i - 1)) != 0 {  // if i is not a power of 2
                    code[i-1] = bytes_iter.next().unwrap_or('0') == '1';
                }
            }

            // set parity bits
            for i in 0..lenpow {
                code[2us.pow(i) - 1] = calc_parity(&code, i);
            }

            code.into_iter().map(|x| if x {"1"} else {"0"}).collect::<Vec<_>>().concat()
        },
        Hamming::Decode => {
            // prompt for binary input
            let code_str = prompt("Enter Hamming code to decode: ");

            // verify parity bits, fix 1-bit-flipped errors if any
            let len = code_str.len();
            let lenpow = ((len + 1) as f32).sqrt().round() as u32;
            let mut chars = code_str.chars().map(|x| x == '1').collect::<Vec<bool>>();
            let mut flipped_bit = -1i32;
            while (0..lenpow).any(|i| calc_parity(&chars, i)) {
                if flipped_bit != -1 {
                    chars[flipped_bit as usize] = !chars[flipped_bit as usize];
                }
                flipped_bit += 1;
                chars[flipped_bit as usize] = !chars[flipped_bit as usize];
            }

            // collect all bits at non-powers-of-2
            let data = &chars.iter().enumerate()
                .filter(|x| ((x.0 + 1) & x.0) != 0).map(|x| if *x.1 {'1'} else {'0'})
                .collect::<Vec<char>>()[..];
            let chars = data.chunks(7)
                .map(|x| u8::from_str_radix(&x.iter().cloned().collect::<String>()[..], 2).unwrap())
                .collect::<Vec<u8>>();

            String::from_utf8(chars).unwrap()
        }
    }
}

fn calc_parity(code: &Vec<bool>, i: u32) -> bool {
    let bi = 2us.pow(i) - 1;
    let (mut parity, mut ignore, mut counter) = (false, false, 0);
    for j in bi..code.len() {
        if !ignore && code[j] { parity = !parity }
        counter += 1;
        if counter >= 2u32.pow(i) {
            ignore = !ignore;
            counter = 0;
        }
    }
    parity
}

fn prompt(s: &str) -> String {
    let mut input = String::new();
    print!("{}", s);
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut input).unwrap();
    input.trim().to_string()
}
<commit_msg>hamming(action) -> hamming(action, s)<commit_after>use std::io;
use std::io::prelude::*;
use std::iter::repeat;
use std::str::FromStr;

enum Hamming { Encode, Decode }

fn main() {
    let title = "RUSTYHAM: A HAMMING CODE GENERATOR IN RUST";
    let border: String = repeat('=').take(title.len()).collect::<>();
    println!("{}", border);
    println!("{}", title);
    println!("{}", border);

    loop {
        let mut linebuf = String::new();
        println!("(1) Encode ASCII");
        println!("*(2) Encode binary");
        println!("(3) Decode to ASCII");
        println!("*(4) Decode to binary");
        println!("Note: options marked as * are not supported yet.");
        print!("Enter your choice: ");
        io::stdout().flush().unwrap();
        io::stdin().read_line(&mut linebuf).unwrap();

        let num = i32::from_str(linebuf.trim());
        match num.ok() {
            Some(n) => {
                let mut good = true;
                println!("{}", match n {
                    1 => hamming(Hamming::Encode, prompt("Enter string to encode: ")),
                    3 => hamming(Hamming::Decode, prompt("Enter Hamming code to decode: ")),
                    2 | 4 => "Sorry, not implemented yet.".to_string(),
                    _ => { good = false; "Invalid input.".to_string() }
                });
                if good { break; }
            }
            None => {
                println!("Invalid input.");
            }
        };
    }
}

fn hamming(action: Hamming, s: String) -> String {
    match action {
        Hamming::Encode => {
            // compute block and message length
            let mlen = s.len() as u32 * 7;
            let lenpow = (2..).find(|&r| 2u32.pow(r) - r - 1 >= mlen).unwrap();
            let len = 2us.pow(lenpow) - 1;

            // the thing we're storing the hamming code in
            let mut code: Vec<bool> = repeat(false).take(len).collect::<>();

            // convert ASCII string to binary
            // IMPORTANT NOTE: the following line takes ownership of the
            // `s' variable. We no longer have access to the original
            // string from this point onwards.
            let bytes = s.into_bytes();
            let bytes_str = bytes.iter().map(|&c| format!("{:0>1$b}", c, 7))
                .collect::<Vec<String>>().concat();

            // set data bits
            let mut bytes_iter = bytes_str.chars();
            for i in 1..len {
                if (i & (i - 1)) != 0 {  // if i is not a power of 2
                    code[i-1] = bytes_iter.next().unwrap_or('0') == '1';
                }
            }

            // set parity bits
            for i in 0..lenpow {
                code[2us.pow(i) - 1] = calc_parity(&code, i);
            }

            code.into_iter().map(|x| if x {"1"} else {"0"}).collect::<Vec<_>>().concat()
        },
        Hamming::Decode => {
            // verify parity bits, fix 1-bit-flipped errors if any
            let len = s.len();
            let lenpow = ((len + 1) as f32).sqrt().round() as u32;
            let mut chars = s.chars().map(|x| x == '1').collect::<Vec<bool>>();
            let mut flipped_bit = -1i32;
            while (0..lenpow).any(|i| calc_parity(&chars, i)) {
                if flipped_bit != -1 {
                    chars[flipped_bit as usize] = !chars[flipped_bit as usize];
                }
                flipped_bit += 1;
                chars[flipped_bit as usize] = !chars[flipped_bit as usize];
            }

            // collect all bits at non-powers-of-2
            let data = &chars.iter().enumerate()
                .filter(|x| ((x.0 + 1) & x.0) != 0).map(|x| if *x.1 {'1'} else {'0'})
                .collect::<Vec<char>>()[..];
            let chars = data.chunks(7)
                .map(|x| u8::from_str_radix(&x.iter().cloned().collect::<String>()[..], 2).unwrap())
                .collect::<Vec<u8>>();

            String::from_utf8(chars).unwrap()
        }
    }
}

fn calc_parity(code: &Vec<bool>, i: u32) -> bool {
    let bi = 2us.pow(i) - 1;
    let (mut parity, mut ignore, mut counter) = (false, false, 0);
    for j in bi..code.len() {
        if !ignore && code[j] { parity = !parity }
        counter += 1;
        if counter >= 2u32.pow(i) {
            ignore = !ignore;
            counter = 0;
        }
    }
    parity
}

fn prompt(s: &str) -> String {
    let mut input = String::new();
    print!("{}", s);
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut input).unwrap();
    input.trim().to_string()
}
<|endoftext|>


<commit_before>use luminance::StageError;
use luminance::shader::stage;
use luminance_gl::gl33::Stage;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::ops::Deref;
use std::path::Path;

pub use luminance::{ProgramError, Sem, Uniformable};
pub use luminance::shader::program::UniformWarning;
pub use luminance_gl::gl33::{self, Uniform};
pub use luminance_gl::gl33::token::GL33;

use resource::{Cache, Load, LoadError, Reload};

#[derive(Debug)]
pub enum ShaderError {
  StageError(StageError),
  ProgramError(ProgramError)
}

pub fn new_program(tcs_src: &str, tes_src: &str, vs_src: &str, gs_src: &str, fs_src: &str, sem_map: &[Sem]) -> Result<(gl33::Program, Vec<UniformWarning>), ProgramError> {
  let stages = compile_stages(tcs_src, tes_src, vs_src, gs_src, fs_src);

  match stages {
    Ok((tess, vs, gs, fs)) => {
      if let Some((tcs, tes)) = tess {
        if let Some(gs) = gs {
          gl33::Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, sem_map)
        } else {
          gl33::Program::new(Some((&tcs, &tes)), &vs, None, &fs, sem_map)
        }
      } else if let Some(gs) = gs {
        gl33::Program::new(None, &vs, Some(&gs), &fs, sem_map)
      } else {
        gl33::Program::new(None, &vs, None, &fs, sem_map)
      }
    },
    Err(stage_error) => {
      Err(ProgramError::LinkFailed(format!("{:?}", stage_error)))
    }
  }
}

// Take raw shader sources and turn them into stages.
fn compile_stages(tcs_src: &str, tes_src: &str, vs_src: &str, gs_src: &str, fs_src: &str) -> Result<(Option<(Stage, Stage)>, Stage, Option<Stage>, Stage), StageError> {
  let tess = if !tcs_src.is_empty() && !tes_src.is_empty() {
    Some((Stage::new(stage::Type::TessellationControlShader, tcs_src)?,
          Stage::new(stage::Type::TessellationEvaluationShader, tes_src)?))
  } else {
    None
  };

  let vs = Stage::new(stage::Type::VertexShader, vs_src)?;
  let gs = if !gs_src.is_empty() { Some(Stage::new(stage::Type::GeometryShader, gs_src)?) } else { None };
  let fs = Stage::new(stage::Type::FragmentShader, fs_src)?;

  Ok((tess, vs, gs, fs))
}

/// Shader program.
///
/// If the program is retrieved from the cache, the path must point to a file containing all the
/// stages. A stage begins with a stage pragma indicating which kind of stage the following source
/// is. Here’s a list of all pragma for each kind of stage:
///
/// - `#tcs`: *tessellation control stage*
/// - `#tes`: *tessellation evaluation stage*
/// - `#vs`: *vertex stage*
/// - `#gs`: *geometry stage*
/// - `#fs`: *fragment stage*
///
/// A stage starts at such a pragma listed above and ends at the next, different pragma. You cannot
/// use twice the same pragma in a file.
///
/// At the top of the file, if you don’t put a pragma, you can use `//` to add comments, or die.
pub struct Program {
  program: gl33::Program,
  sem_map: Vec<Sem>
}

impl Deref for Program {
  type Target = gl33::Program;

  fn deref(&self) -> &Self::Target {
    &self.program
  }
}

impl<'a> Load<'a> for Program {
  type Args = Vec<Sem>;

  fn load<P>(path: P, _: &mut Cache<'a>, args: Self::Args) -> Result<Self, LoadError> where P: AsRef<Path> {
    enum CurrentStage {
      VS,
      FS,
      GS,
      TCS,
      TES
    }

    fn add_line_to_src(src: &mut String, line: &String, line_nb: usize) {
      if src.is_empty() {
        *src += &format!("#line {}\n{}\n", line_nb, line);
      }
    }

    match File::open(path.as_ref()) {
      Ok(fh) => {
        let buffered = BufReader::new(fh);
        let mut tcs_src = String::new();
        let mut tes_src = String::new();
        let mut vs_src = String::new();
        let mut gs_src = String::new();
        let mut fs_src = String::new();
        let mut current_stage: Option<CurrentStage> = None;

        for (line_nb, line) in buffered.lines().enumerate() {
          let line_nb = line_nb + 1;
          let line = line.unwrap();
          let trimmed = line.trim();

          if trimmed.starts_with("#vs") {
            if !vs_src.is_empty() {
              return Err(LoadError::ParseFailed(format!("(line {}) several #vs sections", line_nb)));
            }

            current_stage = Some(CurrentStage::VS);
          } else if trimmed.starts_with("#fs") {
            if !fs_src.is_empty() {
              return Err(LoadError::ParseFailed(format!("(line {}) several #fs sections", line_nb)));
            }

            current_stage = Some(CurrentStage::FS);
          } else if trimmed.starts_with("#gs") {
            if !gs_src.is_empty() {
              return Err(LoadError::ParseFailed(format!("(line {}) several #gs sections", line_nb)));
            }

            current_stage = Some(CurrentStage::GS);
          } else if trimmed.starts_with("#tcs") {
            if !tcs_src.is_empty() {
              return Err(LoadError::ParseFailed(format!("(line {}) several #tcs sections", line_nb)));
            }

            current_stage = Some(CurrentStage::TCS);
          } else if trimmed.starts_with("#tes") {
            if !tes_src.is_empty() {
              return Err(LoadError::ParseFailed(format!("(line {}) several #tes sections", line_nb)));
            }

            current_stage = Some(CurrentStage::TES);
          } else if current_stage.is_none() && !trimmed.starts_with("//") {
            return Err(LoadError::ParseFailed(format!("(line {}) not in a shader stage nor a comment", line_nb)));
          }

          match current_stage {
            Some(CurrentStage::VS) => {
              add_line_to_src(&mut vs_src, &line, line_nb);
            },
            Some(CurrentStage::FS) => {
              add_line_to_src(&mut fs_src, &line, line_nb);
            },
            Some(CurrentStage::GS) => {
              add_line_to_src(&mut gs_src, &line, line_nb);
            },
            Some(CurrentStage::TCS) => {
              add_line_to_src(&mut tcs_src, &line, line_nb);
            },
            Some(CurrentStage::TES) => {
              add_line_to_src(&mut tes_src, &line, line_nb);
            },
            None => {}
          }
        }

        let (program, warnings) = new_program(&tcs_src, &tes_src, &vs_src, &gs_src, &fs_src, &args)
          .map_err(|e| LoadError::ConversionFailed(format!("{:#?}", e)))?;

        // check for semantic errors
        for warning in warnings {
          warn!("uniform warning: {:?}", warning);
        }

        Ok(
          Program {
            program: program,
            sem_map: args
          }
        )
      },
      Err(e) => {
        Err(LoadError::FileNotFound(path.as_ref().to_owned(), format!("{:#?}", e)))
      }
    }
  }
}

impl<'a> Reload<'a> for Program {
  fn reload_args(&self) -> Self::Args {
    self.sem_map.clone()
  }
}

/// A helper function used to make uniforms optionable. If there’s a warning, it’s printed out.
pub fn opt_uni<T>(uni: (Uniform<T>, Option<UniformWarning>)) -> Uniform<T> where T: Uniformable<GL33> {
  if let Some(warning) = uni.1 {
    warn!("{:?}", warning);
  }

  uni.0
}
<commit_msg>Fixed shader parser.<commit_after>use luminance::StageError;
use luminance::shader::stage;
use luminance_gl::gl33::Stage;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::ops::Deref;
use std::path::Path;

pub use luminance::{ProgramError, Sem, Uniformable};
pub use luminance::shader::program::UniformWarning;
pub use luminance_gl::gl33::{self, Uniform};
pub use luminance_gl::gl33::token::GL33;

use resource::{Cache, Load, LoadError, Reload};

#[derive(Debug)]
pub enum ShaderError {
  StageError(StageError),
  ProgramError(ProgramError)
}

pub fn new_program(tcs_src: &str, tes_src: &str, vs_src: &str, gs_src: &str, fs_src: &str, sem_map: &[Sem]) -> Result<(gl33::Program, Vec<UniformWarning>), ProgramError> {
  let stages = compile_stages(tcs_src, tes_src, vs_src, gs_src, fs_src);

  match stages {
    Ok((tess, vs, gs, fs)) => {
      if let Some((tcs, tes)) = tess {
        if let Some(gs) = gs {
          gl33::Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, sem_map)
        } else {
          gl33::Program::new(Some((&tcs, &tes)), &vs, None, &fs, sem_map)
        }
      } else if let Some(gs) = gs {
        gl33::Program::new(None, &vs, Some(&gs), &fs, sem_map)
      } else {
        gl33::Program::new(None, &vs, None, &fs, sem_map)
      }
    },
    Err(stage_error) => {
      Err(ProgramError::LinkFailed(format!("{:?}", stage_error)))
    }
  }
}

// Take raw shader sources and turn them into stages.
fn compile_stages(tcs_src: &str, tes_src: &str, vs_src: &str, gs_src: &str, fs_src: &str) -> Result<(Option<(Stage, Stage)>, Stage, Option<Stage>, Stage), StageError> {
  let tess = if !tcs_src.is_empty() && !tes_src.is_empty() {
    Some((Stage::new(stage::Type::TessellationControlShader, tcs_src)?,
          Stage::new(stage::Type::TessellationEvaluationShader, tes_src)?))
  } else {
    None
  };

  let vs = Stage::new(stage::Type::VertexShader, vs_src)?;
  let gs = if !gs_src.is_empty() { Some(Stage::new(stage::Type::GeometryShader, gs_src)?) } else { None };
  let fs = Stage::new(stage::Type::FragmentShader, fs_src)?;

  Ok((tess, vs, gs, fs))
}

/// Shader program.
///
/// If the program is retrieved from the cache, the path must point to a file containing all the
/// stages. A stage begins with a stage pragma indicating which kind of stage the following source
/// is. Here’s a list of all pragma for each kind of stage:
///
/// - `#tcs`: *tessellation control stage*
/// - `#tes`: *tessellation evaluation stage*
/// - `#vs`: *vertex stage*
/// - `#gs`: *geometry stage*
/// - `#fs`: *fragment stage*
///
/// A stage starts at such a pragma listed above and ends at the next, different pragma. You cannot
/// use twice the same pragma in a file.
///
/// At the top of the file, if you don’t put a pragma, you can use `//` to add comments, or die.
pub struct Program {
  program: gl33::Program,
  sem_map: Vec<Sem>
}

impl Deref for Program {
  type Target = gl33::Program;

  fn deref(&self) -> &Self::Target {
    &self.program
  }
}

impl<'a> Load<'a> for Program {
  type Args = Vec<Sem>;

  fn load<P>(path: P, _: &mut Cache<'a>, args: Self::Args) -> Result<Self, LoadError> where P: AsRef<Path> {
    let path = path.as_ref();

    info!("loading shader: {:?}", path);

    enum CurrentStage {
      VS,
      FS,
      GS,
      TCS,
      TES
    }

    fn add_line_to_src(src: &mut String, line: &str, line_nb: usize) {
      *src += &format!("#line {}\n{}\n", line_nb, line);
    }

    match File::open(path) {
      Ok(fh) => {
        let buffered = BufReader::new(fh);
        let mut tcs_src = String::new();
        let mut tes_src = String::new();
        let mut vs_src = String::new();
        let mut gs_src = String::new();
        let mut fs_src = String::new();
        let mut current_stage: Option<CurrentStage> = None;

        for (line_nb, line) in buffered.lines().enumerate() {
          let line_nb = line_nb + 1;
          let line = line.unwrap();
          let trimmed = line.trim();

          if trimmed.starts_with("#vs") {
            if !vs_src.is_empty() {
              return Err(LoadError::ParseFailed(format!("(line {}) several #vs sections", line_nb)));
            }

            info!("  found a vertex shader");

            current_stage = Some(CurrentStage::VS);
            continue;
          } else if trimmed.starts_with("#fs") {
            if !fs_src.is_empty() {
              return Err(LoadError::ParseFailed(format!("(line {}) several #fs sections", line_nb)));
            }

            info!("  found a fragment shader");

            current_stage = Some(CurrentStage::FS);
            continue;
          } else if trimmed.starts_with("#gs") {
            if !gs_src.is_empty() {
              return Err(LoadError::ParseFailed(format!("(line {}) several #gs sections", line_nb)));
            }

            info!("  found a geometry shader");

            current_stage = Some(CurrentStage::GS);
            continue;
          } else if trimmed.starts_with("#tcs") {
            if !tcs_src.is_empty() {
              return Err(LoadError::ParseFailed(format!("(line {}) several #tcs sections", line_nb)));
            }

            info!("  found a tessellation control shader");

            current_stage = Some(CurrentStage::TCS);
            continue;
          } else if trimmed.starts_with("#tes") {
            if !tes_src.is_empty() {
              return Err(LoadError::ParseFailed(format!("(line {}) several #tes sections", line_nb)));
            }

            info!("  found a tessellation evaluation shader");

            current_stage = Some(CurrentStage::TES);
            continue;
          } else if current_stage.is_none() && !trimmed.is_empty() && !trimmed.starts_with("//") && !trimmed.starts_with("\n") {
            return Err(LoadError::ParseFailed(format!("(line {}) not in a shader stage nor a comment", line_nb)));
          }

          match current_stage {
            Some(CurrentStage::VS) => {
              add_line_to_src(&mut vs_src, trimmed, line_nb);
            },
            Some(CurrentStage::FS) => {
              add_line_to_src(&mut fs_src, trimmed, line_nb);
            },
            Some(CurrentStage::GS) => {
              add_line_to_src(&mut gs_src, trimmed, line_nb);
            },
            Some(CurrentStage::TCS) => {
              add_line_to_src(&mut tcs_src, trimmed, line_nb);
            },
            Some(CurrentStage::TES) => {
              add_line_to_src(&mut tes_src, trimmed, line_nb);
            },
            None => {}
          }
        }

        let (program, warnings) = new_program(&tcs_src, &tes_src, &vs_src, &gs_src, &fs_src, &args)
          .map_err(|e| LoadError::ConversionFailed(format!("{:#?}", e)))?;

        // check for semantic errors
        for warning in warnings {
          warn!("uniform warning: {:?}", warning);
        }

        Ok(
          Program {
            program: program,
            sem_map: args
          }
        )
      },
      Err(e) => {
        Err(LoadError::FileNotFound(path.to_owned(), format!("{:#?}", e)))
      }
    }
  }
}

impl<'a> Reload<'a> for Program {
  fn reload_args(&self) -> Self::Args {
    self.sem_map.clone()
  }
}

/// A helper function used to make uniforms optionable. If there’s a warning, it’s printed out.
pub fn opt_uni<T>(uni: (Uniform<T>, Option<UniformWarning>)) -> Uniform<T> where T: Uniformable<GL33> {
  if let Some(warning) = uni.1 {
    warn!("{:?}", warning);
  }

  uni.0
}
<|endoftext|>