<commit_before>extern crate log;
extern crate env_logger;

extern crate afterparty;
#[macro_use]
extern crate clap;
extern crate lettre;
extern crate git2;
extern crate hyper;
extern crate regex;
extern crate slack_hook;
extern crate toml;

mod auth;
mod config;
mod email;
mod repo;
mod slack;
mod taste;

use afterparty::{Delivery, Event, Hub};
use hyper::Server;
use std::collections::HashMap;
use std::error::Error;
use std::path::Path;
use std::sync::{Arc, Mutex};

use config::Config;

#[cfg_attr(rustfmt, rustfmt_skip)]
const TASTER_USAGE: &'static str = "\
EXAMPLES:
  taste -w /path/to/workdir -s my_secret
  taste -l 0.0.0.0:1234 -w /path/to/workdir -s my_secret";

#[derive(Clone, Debug)]
pub struct Commit {
    pub id: git2::Oid,
    pub msg: String,
    pub url: String,
}

#[derive(Clone, Debug)]
pub struct Push {
    pub head_commit: Commit,
    pub push_ref: Option<String>,
    pub pusher: Option<String>,
}

pub fn main() {
    use clap::{Arg, App};

    env_logger::init().unwrap();

    let args = App::new("taster")
        .version("0.0.1")
        .about("Tastes GitHub commits.")
        .arg(Arg::with_name("listen_addr")
                 .short("l")
                 .long("listen_addr")
                 .takes_value(true)
                 .value_name("IP:PORT")
                 .default_value("0.0.0.0:4567")
                 .help("Listen address and port for webhook delivery"))
        .arg(Arg::with_name("github_repo")
                 .short("r")
                 .long("github_repo")
                 .takes_value(true)
                 .required(true)
                 .value_name("GH_REPO")
                 .default_value("https://github.com/ms705/taster")
                 .help("GitHub repository to taste"))
        .arg(Arg::with_name("email_addr")
                 .long("email_addr")
                 .takes_value(true)
                 .required(false)
                 .help("Email address to send notifications to"))
        .arg(Arg::with_name("default_regression_reporting_threshold")
                 .long("default_regression_reporting_threshold")
                 .takes_value(true)
                 .default_value("0.1")
                 .help("Relative performance threshold below which a result is considered a \
                   regression that needs reporting (0.1 = +/-10%)."))
        .arg(Arg::with_name("default_improvement_reporting_threshold")
                 .long("default_improvement_reporting_threshold")
                 .takes_value(true)
                 .default_value("0.1")
                 .help("Relative performance threshold above which a result is considered an \
                   improvement that needs reporting (0.1 = +/-10%)."))
        .arg(Arg::with_name("secret")
                 .short("s")
                 .long("secret")
                 .takes_value(true)
                 .required(false)
                 .help("GitHub webhook secret"))
        .arg(Arg::with_name("slack_hook_url")
                 .long("slack_hook_url")
                 .takes_value(true)
                 .required(false)
                 .help("Slack webhook URL to push notifications to"))
        .arg(Arg::with_name("slack_channel")
                 .long("slack_channel")
                 .takes_value(true)
                 .required(false)
                 .default_value("#soup-test")
                 .help("Slack channel for notifications"))
        .arg(Arg::with_name("taste_commit")
                 .long("taste_commit")
                 .short("t")
                 .takes_value(true)
                 .required(false)
                 .help("Do a one-off taste of a specific commit"))
        .arg(Arg::with_name("taste_head_only")
                 .long("taste_head_only")
                 .required(false)
                 .help("When multiple commits are pushed, taste the head commit only"))
        .arg(Arg::with_name("verbose_notifications")
                 .long("verbose_notifications")
                 .required(false)
                 .help("List all benchmarks in notifications even if the results have not changed \
                   significantly"))
        .arg(Arg::with_name("workdir")
                 .short("w")
                 .long("workdir")
                 .takes_value(true)
                 .required(true)
                 .value_name("REPO_DIR")
                 .help("Directory holding the workspace repo"))
        .after_help(TASTER_USAGE)
        .get_matches();

    let addr = args.value_of("listen_addr").unwrap();
    let email_notification_addr = args.value_of("email_addr");
    let repo = args.value_of("github_repo").unwrap();
    let secret = args.value_of("secret");
    let slack_hook_url = args.value_of("slack_hook_url");
    let slack_channel = args.value_of("slack_channel");
    let taste_commit = args.value_of("taste_commit");
    let taste_head_only = args.is_present("taste_head_only");
    let workdir = Path::new(args.value_of("workdir").unwrap());
    let verbose_notify = args.is_present("verbose_notifications");
    let improvement_threshold =
        value_t_or_exit!(args, "default_improvement_reporting_threshold", f64);
    let regression_threshold =
        value_t_or_exit!(args, "default_regression_reporting_threshold", f64);

    let mut history = HashMap::new();
    let ws = repo::Workspace::new(repo, workdir);
    let en = if let Some(addr) = email_notification_addr {
        Some(email::EmailNotifier::new(addr, repo))
    } else {
        None
    };
    let sn = if let Some(url) = slack_hook_url {
        Some(slack::SlackNotifier::new(url, slack_channel.unwrap(), repo, verbose_notify))
    } else {
        None
    };

    if taste_commit.is_some() {
        let cid = if let Some("HEAD") = taste_commit {
            ws.repo.head().unwrap().target().unwrap().clone()
        } else {
            git2::Oid::from_str(taste_commit.unwrap()).unwrap()
        };
        match ws.repo.find_object(cid, None) {
            Err(e) => panic!(format!("{}", e.description())),
            Ok(o) => {
                let cobj = o.as_commit().unwrap();
                let hc = Commit {
                    id: cobj.id(),
                    msg: String::from(cobj.message().unwrap()),
                    url: format!("{}/commit/{}", repo, cobj.id()),
                };
                // fake a push
                let push = Push {
                    head_commit: hc,
                    push_ref: None,
                    pusher: None,
                };
                let res = taste::taste_commit(&ws,
                                              &mut history,
                                              &push,
                                              &push.head_commit,
                                              improvement_threshold,
                                              regression_threshold);
                match res {
                    Err(e) => println!("ERROR: failed to taste{}: {}", cid, e),
                    Ok((cfg, tr)) => {
                        // email notification
                        if en.is_some() {
                            en.as_ref()
                                .unwrap()
                                .notify(cfg.as_ref(), &tr, &push)
                                .unwrap();
                        }
                        // slack notification
                        if sn.is_some() {
                            sn.as_ref()
                                .unwrap()
                                .notify(cfg.as_ref(), &tr, &push)
                                .unwrap();
                        }
                        // We're done
                        return;
                    }
                }
            }
        };
    }

    // If we get here, we must be running in continuous mode
    if let None = secret {
        panic!("--secret must be set when in continuous webhook handler mode");
    }

    // Initialize history by tasting the HEAD commit of each branch
    {
        let branches = ws.branch_heads();
        for (b, c) in branches.iter() {
            println!("tasting HEAD of {}: {} / {}",
                     b,
                     c.id(),
                     c.message().unwrap());
            let hc = Commit {
                id: c.id(),
                msg: String::from(c.message().unwrap()),
                url: format!("{}/commit/{}", repo, c.id()),
            };
            // fake a push
            let push = Push {
                head_commit: hc,
                push_ref: Some(b.clone()),
                pusher: None,
            };
            let res = taste::taste_commit(&ws,
                                          &mut history,
                                          &push,
                                          &push.head_commit,
                                          improvement_threshold,
                                          regression_threshold);
            assert!(res.is_ok());
        }
    }

    let hl = Arc::new(Mutex::new(history));
    let wsl = Mutex::new(ws);

    let mut hub = Hub::new();
    hub.handle_authenticated("push", secret.unwrap(), move |delivery: &Delivery| {
        match delivery.payload {
            Event::Push {
                ref _ref,
                ref commits,
                ref head_commit,
                ref pusher,
                ..
            } => {
                println!("Handling {} commits pushed by {}",
                         commits.len(),
                         pusher.name);

                // Data structures to represent info from webhook
                let hc = Commit {
                    id: git2::Oid::from_str(&head_commit.id).unwrap(),
                    msg: head_commit.message.clone(),
                    url: head_commit.url.clone(),
                };
                let push = Push {
                    head_commit: hc,
                    push_ref: Some(_ref.clone()),
                    pusher: Some(pusher.name.clone()),
                };

                let notify = |cfg: Option<&Config>, res: &taste::TastingResult, push: &Push| {
                    // email notification
                    if en.is_some() {
                        en.as_ref().unwrap().notify(cfg, &res, &push).unwrap();
                    }
                    // slack notification
                    if sn.is_some() {
                        sn.as_ref().unwrap().notify(cfg, &res, &push).unwrap();
                    }
                };

                {
                    let ws = wsl.lock().unwrap();
                    let mut history = hl.lock().unwrap();
                    // First taste the head commit
                    ws.fetch().unwrap();
                    let head_res = taste::taste_commit(&ws,
                                                       &mut history,
                                                       &push,
                                                       &push.head_commit,
                                                       improvement_threshold,
                                                       regression_threshold);
                    match head_res {
                        Err(e) => {
                            println!("ERROR: failed to taste HEAD commit {}: {}",
                                     head_commit.id,
                                     e)
                        }
                        Ok((cfg, tr)) => {
                            notify(cfg.as_ref(), &tr, &push);
                            // Taste others if needed
                            if !taste_head_only {
                                for c in commits.iter() {
                                    if c.id == head_commit.id {
                                        // skip HEAD as we've already tested it
                                        continue;
                                    }
                                    let cur_c = Commit {
                                        id: git2::Oid::from_str(&c.id).unwrap(),
                                        msg: c.message.clone(),
                                        url: c.url.clone(),
                                    };
                                    // taste
                                    let res = taste::taste_commit(&ws,
                                                                  &mut history,
                                                                  &push,
                                                                  &cur_c,
                                                                  improvement_threshold,
                                                                  regression_threshold);
                                    match res {
                                        Err(e) => {
                                            println!("ERROR: failed to taste commit {}: {}",
                                                     c.id,
                                                     e)
                                        }
                                        Ok((cfg, tr)) => notify(cfg.as_ref(), &tr, &push),
                                    }
                                }
                            } else if !commits.is_empty() {
                                println!("Skipping {} remaining commits in push!",
                                         commits.len() - 1);
                            }
                        }
                    }
                }
            }
            _ => (),
        }
    });

    let srvc = Server::http(&addr[..]).unwrap().handle(hub);

    println!("Taster listening on {}", addr);
    srvc.unwrap();
}
<commit_msg>Fix typo in README<commit_after>extern crate log;
extern crate env_logger;

extern crate afterparty;
#[macro_use]
extern crate clap;
extern crate lettre;
extern crate git2;
extern crate hyper;
extern crate regex;
extern crate slack_hook;
extern crate toml;

mod auth;
mod config;
mod email;
mod repo;
mod slack;
mod taste;

use afterparty::{Delivery, Event, Hub};
use hyper::Server;
use std::collections::HashMap;
use std::error::Error;
use std::path::Path;
use std::sync::{Arc, Mutex};

use config::Config;

#[cfg_attr(rustfmt, rustfmt_skip)]
const TASTER_USAGE: &'static str = "\
EXAMPLES:
  taster -w /path/to/workdir -s my_secret
  taster -l 0.0.0.0:1234 -w /path/to/workdir -s my_secret";

#[derive(Clone, Debug)]
pub struct Commit {
    pub id: git2::Oid,
    pub msg: String,
    pub url: String,
}

#[derive(Clone, Debug)]
pub struct Push {
    pub head_commit: Commit,
    pub push_ref: Option<String>,
    pub pusher: Option<String>,
}

pub fn main() {
    use clap::{Arg, App};

    env_logger::init().unwrap();

    let args = App::new("taster")
        .version("0.0.1")
        .about("Tastes GitHub commits.")
        .arg(Arg::with_name("listen_addr")
                 .short("l")
                 .long("listen_addr")
                 .takes_value(true)
                 .value_name("IP:PORT")
                 .default_value("0.0.0.0:4567")
                 .help("Listen address and port for webhook delivery"))
        .arg(Arg::with_name("github_repo")
                 .short("r")
                 .long("github_repo")
                 .takes_value(true)
                 .required(true)
                 .value_name("GH_REPO")
                 .default_value("https://github.com/ms705/taster")
                 .help("GitHub repository to taste"))
        .arg(Arg::with_name("email_addr")
                 .long("email_addr")
                 .takes_value(true)
                 .required(false)
                 .help("Email address to send notifications to"))
        .arg(Arg::with_name("default_regression_reporting_threshold")
                 .long("default_regression_reporting_threshold")
                 .takes_value(true)
                 .default_value("0.1")
                 .help("Relative performance threshold below which a result is considered a \
                   regression that needs reporting (0.1 = +/-10%)."))
        .arg(Arg::with_name("default_improvement_reporting_threshold")
                 .long("default_improvement_reporting_threshold")
                 .takes_value(true)
                 .default_value("0.1")
                 .help("Relative performance threshold above which a result is considered an \
                   improvement that needs reporting (0.1 = +/-10%)."))
        .arg(Arg::with_name("secret")
                 .short("s")
                 .long("secret")
                 .takes_value(true)
                 .required(false)
                 .help("GitHub webhook secret"))
        .arg(Arg::with_name("slack_hook_url")
                 .long("slack_hook_url")
                 .takes_value(true)
                 .required(false)
                 .help("Slack webhook URL to push notifications to"))
        .arg(Arg::with_name("slack_channel")
                 .long("slack_channel")
                 .takes_value(true)
                 .required(false)
                 .default_value("#soup-test")
                 .help("Slack channel for notifications"))
        .arg(Arg::with_name("taste_commit")
                 .long("taste_commit")
                 .short("t")
                 .takes_value(true)
                 .required(false)
                 .help("Do a one-off taste of a specific commit"))
        .arg(Arg::with_name("taste_head_only")
                 .long("taste_head_only")
                 .required(false)
                 .help("When multiple commits are pushed, taste the head commit only"))
        .arg(Arg::with_name("verbose_notifications")
                 .long("verbose_notifications")
                 .required(false)
                 .help("List all benchmarks in notifications even if the results have not changed \
                   significantly"))
        .arg(Arg::with_name("workdir")
                 .short("w")
                 .long("workdir")
                 .takes_value(true)
                 .required(true)
                 .value_name("REPO_DIR")
                 .help("Directory holding the workspace repo"))
        .after_help(TASTER_USAGE)
        .get_matches();

    let addr = args.value_of("listen_addr").unwrap();
    let email_notification_addr = args.value_of("email_addr");
    let repo = args.value_of("github_repo").unwrap();
    let secret = args.value_of("secret");
    let slack_hook_url = args.value_of("slack_hook_url");
    let slack_channel = args.value_of("slack_channel");
    let taste_commit = args.value_of("taste_commit");
    let taste_head_only = args.is_present("taste_head_only");
    let workdir = Path::new(args.value_of("workdir").unwrap());
    let verbose_notify = args.is_present("verbose_notifications");
    let improvement_threshold =
        value_t_or_exit!(args, "default_improvement_reporting_threshold", f64);
    let regression_threshold =
        value_t_or_exit!(args, "default_regression_reporting_threshold", f64);

    let mut history = HashMap::new();
    let ws = repo::Workspace::new(repo, workdir);
    let en = if let Some(addr) = email_notification_addr {
        Some(email::EmailNotifier::new(addr, repo))
    } else {
        None
    };
    let sn = if let Some(url) = slack_hook_url {
        Some(slack::SlackNotifier::new(url, slack_channel.unwrap(), repo, verbose_notify))
    } else {
        None
    };

    if taste_commit.is_some() {
        let cid = if let Some("HEAD") = taste_commit {
            ws.repo.head().unwrap().target().unwrap().clone()
        } else {
            git2::Oid::from_str(taste_commit.unwrap()).unwrap()
        };
        match ws.repo.find_object(cid, None) {
            Err(e) => panic!(format!("{}", e.description())),
            Ok(o) => {
                let cobj = o.as_commit().unwrap();
                let hc = Commit {
                    id: cobj.id(),
                    msg: String::from(cobj.message().unwrap()),
                    url: format!("{}/commit/{}", repo, cobj.id()),
                };
                // fake a push
                let push = Push {
                    head_commit: hc,
                    push_ref: None,
                    pusher: None,
                };
                let res = taste::taste_commit(&ws,
                                              &mut history,
                                              &push,
                                              &push.head_commit,
                                              improvement_threshold,
                                              regression_threshold);
                match res {
                    Err(e) => println!("ERROR: failed to taste{}: {}", cid, e),
                    Ok((cfg, tr)) => {
                        // email notification
                        if en.is_some() {
                            en.as_ref()
                                .unwrap()
                                .notify(cfg.as_ref(), &tr, &push)
                                .unwrap();
                        }
                        // slack notification
                        if sn.is_some() {
                            sn.as_ref()
                                .unwrap()
                                .notify(cfg.as_ref(), &tr, &push)
                                .unwrap();
                        }
                        // We're done
                        return;
                    }
                }
            }
        };
    }

    // If we get here, we must be running in continuous mode
    if let None = secret {
        panic!("--secret must be set when in continuous webhook handler mode");
    }

    // Initialize history by tasting the HEAD commit of each branch
    {
        let branches = ws.branch_heads();
        for (b, c) in branches.iter() {
            println!("tasting HEAD of {}: {} / {}",
                     b,
                     c.id(),
                     c.message().unwrap());
            let hc = Commit {
                id: c.id(),
                msg: String::from(c.message().unwrap()),
                url: format!("{}/commit/{}", repo, c.id()),
            };
            // fake a push
            let push = Push {
                head_commit: hc,
                push_ref: Some(b.clone()),
                pusher: None,
            };
            let res = taste::taste_commit(&ws,
                                          &mut history,
                                          &push,
                                          &push.head_commit,
                                          improvement_threshold,
                                          regression_threshold);
            assert!(res.is_ok());
        }
    }

    let hl = Arc::new(Mutex::new(history));
    let wsl = Mutex::new(ws);

    let mut hub = Hub::new();
    hub.handle_authenticated("push", secret.unwrap(), move |delivery: &Delivery| {
        match delivery.payload {
            Event::Push {
                ref _ref,
                ref commits,
                ref head_commit,
                ref pusher,
                ..
            } => {
                println!("Handling {} commits pushed by {}",
                         commits.len(),
                         pusher.name);

                // Data structures to represent info from webhook
                let hc = Commit {
                    id: git2::Oid::from_str(&head_commit.id).unwrap(),
                    msg: head_commit.message.clone(),
                    url: head_commit.url.clone(),
                };
                let push = Push {
                    head_commit: hc,
                    push_ref: Some(_ref.clone()),
                    pusher: Some(pusher.name.clone()),
                };

                let notify = |cfg: Option<&Config>, res: &taste::TastingResult, push: &Push| {
                    // email notification
                    if en.is_some() {
                        en.as_ref().unwrap().notify(cfg, &res, &push).unwrap();
                    }
                    // slack notification
                    if sn.is_some() {
                        sn.as_ref().unwrap().notify(cfg, &res, &push).unwrap();
                    }
                };

                {
                    let ws = wsl.lock().unwrap();
                    let mut history = hl.lock().unwrap();
                    // First taste the head commit
                    ws.fetch().unwrap();
                    let head_res = taste::taste_commit(&ws,
                                                       &mut history,
                                                       &push,
                                                       &push.head_commit,
                                                       improvement_threshold,
                                                       regression_threshold);
                    match head_res {
                        Err(e) => {
                            println!("ERROR: failed to taste HEAD commit {}: {}",
                                     head_commit.id,
                                     e)
                        }
                        Ok((cfg, tr)) => {
                            notify(cfg.as_ref(), &tr, &push);
                            // Taste others if needed
                            if !taste_head_only {
                                for c in commits.iter() {
                                    if c.id == head_commit.id {
                                        // skip HEAD as we've already tested it
                                        continue;
                                    }
                                    let cur_c = Commit {
                                        id: git2::Oid::from_str(&c.id).unwrap(),
                                        msg: c.message.clone(),
                                        url: c.url.clone(),
                                    };
                                    // taste
                                    let res = taste::taste_commit(&ws,
                                                                  &mut history,
                                                                  &push,
                                                                  &cur_c,
                                                                  improvement_threshold,
                                                                  regression_threshold);
                                    match res {
                                        Err(e) => {
                                            println!("ERROR: failed to taste commit {}: {}",
                                                     c.id,
                                                     e)
                                        }
                                        Ok((cfg, tr)) => notify(cfg.as_ref(), &tr, &push),
                                    }
                                }
                            } else if !commits.is_empty() {
                                println!("Skipping {} remaining commits in push!",
                                         commits.len() - 1);
                            }
                        }
                    }
                }
            }
            _ => (),
        }
    });

    let srvc = Server::http(&addr[..]).unwrap().handle(hub);

    println!("Taster listening on {}", addr);
    srvc.unwrap();
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use types::Type;

#[derive( Debug)]
pub enum AST {
    Int(i32),
    Float(f64),
    Char(i32),
    String(String),
    Variable(String),
    VariableDecl(Type, String, Option<Rc<AST>>), // type, name, init val
    UnaryOp(Rc<AST>, CUnaryOps),
    BinaryOp(Rc<AST>, Rc<AST>, CBinOps),
    FuncDef(Type, Vec<String>, String, Rc<AST>), // functype, param names, func name, body
    Block(Vec<AST>),
    FuncCall(Rc<AST>, Vec<AST>),
    StructRef(Rc<AST>, String), // String is name of struct field
    Return(Option<Rc<AST>>),
}

#[derive(Debug)]
pub enum CBinOps {
    Add,
    Sub,
    Mul,
    Div,
    Rem,
    And,
    Or,
    Xor,
    LAnd,
    LOr,
    Eq,
    Ne,
    Lt,
    Gt,
    Le,
    Ge,
    Shl,
    Shr,
    Comma,
    Assign,
}

#[derive(Debug)]
pub enum CUnaryOps {
    LNot,
    BNot,
    Plus,
    Minus,
    Inc,
    Dec,
    Deref,
    Addr,
    // TODO: add Cast, Sizeof
}

impl AST {
    pub fn eval_constexpr(&self) -> i32 {
        match self {
            &AST::Int(n) => n,
            &AST::UnaryOp(ref aexpr, ref op) => {
                let expr = aexpr.eval_constexpr();
                match op {
                    &CUnaryOps::LNot => (expr == 0) as i32,
                    &CUnaryOps::BNot => !expr,
                    &CUnaryOps::Plus => expr,
                    &CUnaryOps::Minus => -expr,
                    &CUnaryOps::Inc => 1 + expr,
                    &CUnaryOps::Dec => expr - 1,
                    &CUnaryOps::Deref => expr,
                    &CUnaryOps::Addr => expr,
                }
            }
            &AST::BinaryOp(ref alhs, ref arhs, ref op) => {
                let lhs = alhs.eval_constexpr();
                let rhs = arhs.eval_constexpr();
                match op {
                    &CBinOps::Add => lhs + rhs,
                    &CBinOps::Sub => lhs - rhs,
                    &CBinOps::Mul => lhs * rhs,
                    &CBinOps::Div => lhs / rhs,
                    &CBinOps::Rem => lhs % rhs,
                    &CBinOps::And => lhs & rhs,
                    &CBinOps::Or => lhs | rhs,
                    &CBinOps::Xor => lhs ^ rhs,
                    &CBinOps::LAnd => lhs & rhs,
                    &CBinOps::LOr => lhs | rhs,
                    &CBinOps::Eq => (lhs == rhs) as i32,
                    &CBinOps::Ne => (lhs != rhs) as i32,
                    &CBinOps::Lt => (lhs < rhs) as i32,
                    &CBinOps::Gt => (lhs > rhs) as i32,
                    &CBinOps::Le => (lhs <= rhs) as i32,
                    &CBinOps::Ge => (lhs >= rhs) as i32,
                    &CBinOps::Shl => lhs << rhs,
                    &CBinOps::Shr => lhs >> rhs,
                    &CBinOps::Comma => rhs,
                    _ => 0,
                }
            }
            _ => 0,
        }
    }
    pub fn show(&self) {
        match self {
            &AST::Int(n) => print!("{} ", n),
            &AST::Float(n) => print!("{} ", n),
            &AST::Char(c) => print!("'{}' ", c),
            &AST::String(ref s) => print!("\"{}\" ", s),
            &AST::Variable(ref name) => print!("{} ", name),
            &AST::VariableDecl(ref ty, ref name, ref init) => {
                print!("(var-decl {:?} {}", ty, name);
                if init.is_some() {
                    print!(" (init ");
                    init.clone().unwrap().show();
                    print!(")");
                }
                print!(")");
            }
            &AST::UnaryOp(ref expr, ref op) => {
                print!("({:?} ", op);
                expr.show();
                print!(")");
            }
            &AST::BinaryOp(ref lhs, ref rhs, ref op) => {
                print!("({:?} ", op);
                lhs.show();
                rhs.show();
                print!(")");
            }
            &AST::FuncDef(ref functy, ref param_names, ref name, ref body) => {
                print!("(def-func {} {:?} {:?}", name, functy, param_names);
                body.show();
                print!(")");
            }
            &AST::Block(ref body) => {
                for stmt in body {
                    stmt.show();
                }
            }
            &AST::FuncCall(ref f, ref args) => {
                print!("(func-call ");
                f.show();
                print!(" ");
                for arg in args {
                    arg.show();
                }
                print!(")");
            }
            &AST::StructRef(ref s, ref field) => {
                print!("(struct-ref ");
                s.show();
                print!(" {})", field);
            }
            &AST::Return(ref retval) => {
                print!("(return ");
                if retval.is_some() {
                    retval.clone().unwrap().show();
                }
                print!(")");
            }
        };
    }
}
<commit_msg>changed eval_constexpr on node.rs<commit_after>use std::rc::Rc;
use types::Type;

#[derive( Debug)]
pub enum AST {
    Int(i32),
    Float(f64),
    Char(i32),
    String(String),
    Variable(String),
    VariableDecl(Type, String, Option<Rc<AST>>), // type, name, init val
    UnaryOp(Rc<AST>, CUnaryOps),
    BinaryOp(Rc<AST>, Rc<AST>, CBinOps),
    FuncDef(Type, Vec<String>, String, Rc<AST>), // functype, param names, func name, body
    Block(Vec<AST>),
    FuncCall(Rc<AST>, Vec<AST>),
    StructRef(Rc<AST>, String), // String is name of struct field
    Return(Option<Rc<AST>>),
}

#[derive(Debug)]
pub enum CBinOps {
    Add,
    Sub,
    Mul,
    Div,
    Rem,
    And,
    Or,
    Xor,
    LAnd,
    LOr,
    Eq,
    Ne,
    Lt,
    Gt,
    Le,
    Ge,
    Shl,
    Shr,
    Comma,
    Assign,
}

#[derive(Debug)]
pub enum CUnaryOps {
    LNot,
    BNot,
    Plus,
    Minus,
    Inc,
    Dec,
    Deref,
    Addr,
    // TODO: add Cast, Sizeof
}

impl AST {
    pub fn eval_constexpr(&self) -> i32 { self.eval() }

    fn eval(&self) -> i32 {
        match self {
            &AST::Int(n) => n,
            &AST::UnaryOp(ref e, CUnaryOps::LNot) => (e.eval() == 0) as i32,
            &AST::UnaryOp(ref e, CUnaryOps::BNot) => !e.eval(),
            &AST::UnaryOp(ref e, CUnaryOps::Plus) => e.eval(),
            &AST::UnaryOp(ref e, CUnaryOps::Minus) => -e.eval(),
            &AST::UnaryOp(ref e, CUnaryOps::Inc) => e.eval() + 1,
            &AST::UnaryOp(ref e, CUnaryOps::Dec) => e.eval() - 1,
            &AST::UnaryOp(ref e, CUnaryOps::Deref) => e.eval(),
            &AST::UnaryOp(ref e, CUnaryOps::Addr) => e.eval(),
            &AST::BinaryOp(ref l, ref r, CBinOps::Add) => l.eval() + r.eval(),
            &AST::BinaryOp(ref l, ref r, CBinOps::Sub) => l.eval() - r.eval(),
            &AST::BinaryOp(ref l, ref r, CBinOps::Mul) => l.eval() * r.eval(),
            &AST::BinaryOp(ref l, ref r, CBinOps::Div) => l.eval() / r.eval(),
            &AST::BinaryOp(ref l, ref r, CBinOps::Rem) => l.eval() % r.eval(),
            &AST::BinaryOp(ref l, ref r, CBinOps::And) => l.eval() & r.eval(),
            &AST::BinaryOp(ref l, ref r, CBinOps::Or) => l.eval() | r.eval(),
            &AST::BinaryOp(ref l, ref r, CBinOps::Xor) => l.eval() ^ r.eval(),
            &AST::BinaryOp(ref l, ref r, CBinOps::LAnd) => l.eval() & r.eval(),
            &AST::BinaryOp(ref l, ref r, CBinOps::LOr) => l.eval() | r.eval(),
            &AST::BinaryOp(ref l, ref r, CBinOps::Eq) => (l.eval() == r.eval()) as i32,
            &AST::BinaryOp(ref l, ref r, CBinOps::Ne) => (l.eval() != r.eval()) as i32,
            &AST::BinaryOp(ref l, ref r, CBinOps::Lt) => (l.eval() < r.eval()) as i32,
            &AST::BinaryOp(ref l, ref r, CBinOps::Gt) => (l.eval() > r.eval()) as i32,
            &AST::BinaryOp(ref l, ref r, CBinOps::Le) => (l.eval() <= r.eval()) as i32,
            &AST::BinaryOp(ref l, ref r, CBinOps::Ge) => (l.eval() >= r.eval()) as i32,
            &AST::BinaryOp(ref l, ref r, CBinOps::Shl) => l.eval() << r.eval(),
            &AST::BinaryOp(ref l, ref r, CBinOps::Shr) => l.eval() >> r.eval(),
            &AST::BinaryOp(ref l, ref r, CBinOps::Comma) => {l.eval(); r.eval()},
            &AST::BinaryOp(ref l, ref r, _) => {l.eval(); r.eval(); 0},
            _ => 0,
        }
    }
    pub fn show(&self) {
        match self {
            &AST::Int(n) => print!("{} ", n),
            &AST::Float(n) => print!("{} ", n),
            &AST::Char(c) => print!("'{}' ", c),
            &AST::String(ref s) => print!("\"{}\" ", s),
            &AST::Variable(ref name) => print!("{} ", name),
            &AST::VariableDecl(ref ty, ref name, ref init) => {
                print!("(var-decl {:?} {}", ty, name);
                if init.is_some() {
                    print!(" (init ");
                    init.clone().unwrap().show();
                    print!(")");
                }
                print!(")");
            }
            &AST::UnaryOp(ref expr, ref op) => {
                print!("({:?} ", op);
                expr.show();
                print!(")");
            }
            &AST::BinaryOp(ref lhs, ref rhs, ref op) => {
                print!("({:?} ", op);
                lhs.show();
                rhs.show();
                print!(")");
            }
            &AST::FuncDef(ref functy, ref param_names, ref name, ref body) => {
                print!("(def-func {} {:?} {:?}", name, functy, param_names);
                body.show();
                print!(")");
            }
            &AST::Block(ref body) => {
                for stmt in body {
                    stmt.show();
                }
            }
            &AST::FuncCall(ref f, ref args) => {
                print!("(func-call ");
                f.show();
                print!(" ");
                for arg in args {
                    arg.show();
                }
                print!(")");
            }
            &AST::StructRef(ref s, ref field) => {
                print!("(struct-ref ");
                s.show();
                print!(" {})", field);
            }
            &AST::Return(ref retval) => {
                print!("(return ");
                if retval.is_some() {
                    retval.clone().unwrap().show();
                }
                print!(")");
            }
        };
    }
}
<|endoftext|>


<commit_before>
use buffer::DspBuffer;
use sound_stream::{
    AudioBuffer,
    Sample,
    Settings,
};
use std::num::Float;

/// The amplitude multiplier.
pub type Volume = f32;
/// The spacial positioning of the node. Currently only supports Stereo or Mono.
/// -1.0 = Left.
///  0.0 = Center.
///  1.0 = Right.
pub type Panning = f32;

/// DSP Node trait. Implement this for any audio instrument or effects types that are to be used
/// within your DSP chain. Override all methods that you wish. If the Node is a parent of other
/// DSP nodes, be sure to implement the `inputs` method.
pub trait Node<B, O> where B: DspBuffer<O>, O: Sample {

    /// Return the volume for this Node.
    #[inline]
    fn vol(&self) -> Volume { 1.0 }

    /// Return the panning for this Node.
    /// -1.0 = Left.
    ///  0.0 = Center.
    ///  1.0 = Right.
    #[inline]
    fn pan(&self) -> Panning { 0.0 }

    /// Return mutable references to the inputs for the Node.
    /// TODO: Once "Abstract Return Types" land in Rust, we'll
    /// change this to return `impl Iterator<&mut Node<B, O>>`
    /// so that we don't have to allocate *anything* in the
    /// whole graph.
    #[inline]
    fn inputs(&mut self) -> Vec<&mut Node<B, O>> { Vec::new() }

    /// Determine the volume for each channel by considering
    /// both `vol` and `pan. In the future this will be
    /// replaced with an `n` channels method.
    #[inline]
    fn vol_per_channel(&self) -> [f32, ..2] {
        if self.pan() >= 0.0 {
            [self.vol() * (self.pan() - 1.0).abs(), self.vol()]
        } else {
            [self.vol(), self.vol() * (self.pan() + 1.0)]
        }
    }

    /// Request audio from inputs, process and
    /// pass back to the output! Override this
    /// method for any synthesis or generative
    /// types.
    #[inline]
    fn audio_requested(&mut self, output: &mut B, settings: Settings) {
        let frames = settings.frames as uint;
        let channels = settings.channels as uint;
        let buffer_size = frames * channels;
        let vol_per_channel = self.vol_per_channel();
        for input in self.inputs().into_iter() {
            let mut working: B = AudioBuffer::zeroed(buffer_size);
            // Call audio_requested for each input.
            input.audio_requested(&mut working, settings);
            // Sum all input nodes to output (considering pan, vol and interleaving).
            for i in range(0, frames) {
                for j in range(0, channels) {
                    use std::num::from_f32;
                    let idx = i * channels + j;
                    let working_f32 = working.val(idx).to_f32().unwrap();
                    let working_sample = from_f32(working_f32 * vol_per_channel[j]).unwrap();
                    *output.get_mut(idx) = output.val(idx) + working_sample;
                }
            }
        }
        // Custom buffer processing.
        self.process_buffer(output, settings);
    }

    /// Override for custom processing of audio per
    /// buffer. This is mainly for audio effects. Get's
    /// called at the end of audio_requested.
    #[inline]
    fn process_buffer(&mut self, _output: &mut B, _settings: Settings) {}

}

/// A trait for types who are designed to receive audio from an incoming stream.
pub trait InputNode<I> where I: Sample {
    /// Receive incoming audio (implement this to do something with the input).
    #[inline]
    fn audio_received<I>(&mut self, _input: &Vec<I>, _settings: Settings) where I: Sample;
}

<commit_msg>Removed unnecessary type param from audio_received method<commit_after>
use buffer::DspBuffer;
use sound_stream::{
    AudioBuffer,
    Sample,
    Settings,
};
use std::num::Float;

/// The amplitude multiplier.
pub type Volume = f32;
/// The spacial positioning of the node. Currently only supports Stereo or Mono.
/// -1.0 = Left.
///  0.0 = Center.
///  1.0 = Right.
pub type Panning = f32;

/// DSP Node trait. Implement this for any audio instrument or effects types that are to be used
/// within your DSP chain. Override all methods that you wish. If the Node is a parent of other
/// DSP nodes, be sure to implement the `inputs` method.
pub trait Node<B, O> where B: DspBuffer<O>, O: Sample {

    /// Return the volume for this Node.
    #[inline]
    fn vol(&self) -> Volume { 1.0 }

    /// Return the panning for this Node.
    /// -1.0 = Left.
    ///  0.0 = Center.
    ///  1.0 = Right.
    #[inline]
    fn pan(&self) -> Panning { 0.0 }

    /// Return mutable references to the inputs for the Node.
    /// TODO: Once "Abstract Return Types" land in Rust, we'll
    /// change this to return `impl Iterator<&mut Node<B, O>>`
    /// so that we don't have to allocate *anything* in the
    /// whole graph.
    #[inline]
    fn inputs(&mut self) -> Vec<&mut Node<B, O>> { Vec::new() }

    /// Determine the volume for each channel by considering
    /// both `vol` and `pan. In the future this will be
    /// replaced with an `n` channels method.
    #[inline]
    fn vol_per_channel(&self) -> [f32, ..2] {
        if self.pan() >= 0.0 {
            [self.vol() * (self.pan() - 1.0).abs(), self.vol()]
        } else {
            [self.vol(), self.vol() * (self.pan() + 1.0)]
        }
    }

    /// Request audio from inputs, process and
    /// pass back to the output! Override this
    /// method for any synthesis or generative
    /// types.
    #[inline]
    fn audio_requested(&mut self, output: &mut B, settings: Settings) {
        let frames = settings.frames as uint;
        let channels = settings.channels as uint;
        let buffer_size = frames * channels;
        let vol_per_channel = self.vol_per_channel();
        for input in self.inputs().into_iter() {
            let mut working: B = AudioBuffer::zeroed(buffer_size);
            // Call audio_requested for each input.
            input.audio_requested(&mut working, settings);
            // Sum all input nodes to output (considering pan, vol and interleaving).
            for i in range(0, frames) {
                for j in range(0, channels) {
                    use std::num::from_f32;
                    let idx = i * channels + j;
                    let working_f32 = working.val(idx).to_f32().unwrap();
                    let working_sample = from_f32(working_f32 * vol_per_channel[j]).unwrap();
                    *output.get_mut(idx) = output.val(idx) + working_sample;
                }
            }
        }
        // Custom buffer processing.
        self.process_buffer(output, settings);
    }

    /// Override for custom processing of audio per
    /// buffer. This is mainly for audio effects. Get's
    /// called at the end of audio_requested.
    #[inline]
    fn process_buffer(&mut self, _output: &mut B, _settings: Settings) {}

}

/// A trait for types who are designed to receive audio from an incoming stream.
pub trait InputNode<I> where I: Sample {
    /// Receive incoming audio (implement this to do something with the input).
    #[inline]
    fn audio_received(&mut self, _input: &Vec<I>, _settings: Settings) where I: Sample;
}

<|endoftext|>


<commit_before>use std::marker::PhantomData;

use num::BigUint;

use Construct;
use Data;
use Count;
use Of;
use ToIndex;
use ToPos;
use Zero;

/// Dimension is natural number, position is (min, max).
pub struct Pair<T = Data>(PhantomData<T>);

impl<T> Construct for Pair<T> {
    fn new() -> Pair<T> { Pair(PhantomData) }
}

impl Count<usize> for Pair<Data> {
    type N = usize;
    fn count(&self, dim: &usize) -> usize { dim * (dim - 1) / 2 }
}

impl Count<BigUint> for Pair<Data> {
    type N = BigUint;
    fn count(&self, dim: &BigUint) -> BigUint {
        let _1: BigUint = 1usize.into();
        let _2: BigUint = 2usize.into();
        dim * (dim - _1) / _2
    }
}

impl<T, U> Count<U> for Pair<Of<T>>
    where
        T: Construct + Count<U>,
        Pair: Count<<T as Count<U>>::N, N = <T as Count<U>>::N>
{
    type N = <T as Count<U>>::N;
    fn count(&self, dim: &U) -> Self::N {
        let of: T = Construct::new();
        let data: Pair<Data> = Construct::new();
        data.count(&of.count(dim))
    }
}

impl Zero<usize, (usize, usize)> for Pair<Data> {
    fn zero(&self, _dim: &usize) -> (usize, usize) { (0, 0) }
}

impl<T, U, V>
Zero<U, (V, V)> for Pair<Of<T>>
    where T: Construct + Zero<U, V>
{
    fn zero(&self, dim: &U) -> (V, V) {
        let of: T = Construct::new();
        (of.zero(dim), of.zero(dim))
    }
}

impl ToIndex<usize, (usize, usize)>
for Pair<Data> {
    fn to_index(&self, _dim: &usize, &(min, max): &(usize, usize)) -> usize {
        min + max * (max - 1) / 2
    }
}

impl<T, U, V>
ToIndex<U, (V, V)> for Pair<Of<T>>
    where T: Construct + ToIndex<U, V> + Count<U, N = usize>
{
    fn to_index(
        &self,
        dim: &U,
        &(ref min, ref max): &(V, V)
    ) -> usize {
        let of: T = Construct::new();
        let data: Pair<Data> = Construct::new();
        let min = of.to_index(dim, min);
        let max = of.to_index(dim, max);
        data.to_index(&self.count(dim), &(min, max))
    }
}

impl ToPos<usize, (usize, usize)> for Pair<Data> {
    fn to_pos(&self, _dim: &usize, index: usize, pos: &mut (usize, usize)) {
        let max = ((-1f64 + (8f64 * index as f64 + 1f64).sqrt()) / 2f64) as usize + 1;
        let min = index.wrapping_sub(max * (max + 1) / 2).wrapping_add(max);
        *pos = (min, max)
    }
}

impl<T, U, V>
ToPos<U, (V, V)> for Pair<Of<T>>
    where T: Construct + Count<U, N = usize> + ToPos<U, V>
{
    fn to_pos(
        &self,
        dim: &U,
        index: usize,
        &mut (ref mut min, ref mut max): &mut (V, V)
    ) {
        let of: T = Construct::new();
        let data: Pair<Data> = Construct::new();
        let count = of.count(dim);
        let mut pair = (0, 0);
        data.to_pos(&count, index, &mut pair);
        let (pair_min, pair_max) = pair;
        of.to_pos(dim, pair_min, min);
        of.to_pos(dim, pair_max, max);
    }
}

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

    #[test]
    fn features() {
        is_complete::<Pair, usize, (usize, usize)>();
        is_complete::<Pair<Of<Pair>>, usize,
            ((usize, usize), (usize, usize))>();
    }

    #[test]
    fn data() {
        let x: Pair = Construct::new();
        let ref dim = 4;
        assert_eq!(x.count(dim), 6);
        assert_eq!(x.to_index(dim, &(0, 1)), 0);
        assert_eq!(x.to_index(dim, &(0, 2)), 1);
        assert_eq!(x.to_index(dim, &(1, 2)), 2);
        assert_eq!(x.to_index(dim, &(0, 3)), 3);
        let mut new_pos = (0, 0);
        x.to_pos(dim, 3, &mut new_pos);
        assert_eq!(new_pos, (0, 3));
    }

    #[test]
    fn of() {
        let x: Pair<Of<DimensionN>> = Construct::new();
        let ref dim = vec![2, 2];
        assert_eq!(x.count(dim), 6);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 0])), 0);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![0, 1])), 1);
        assert_eq!(x.to_index(dim, &(vec![1, 0], vec![0, 1])), 2);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 1])), 3);
        assert_eq!(x.to_index(dim, &(vec![1, 0], vec![1, 1])), 4);
        assert_eq!(x.to_index(dim, &(vec![0, 1], vec![1, 1])), 5);
        let mut pos = (Vec::new(), Vec::new());
        for i in 0..6 {
            x.to_pos(dim, i, &mut pos);
            // println!("{} {}", &min[], &max[]);
        }
        x.to_pos(dim, 5, &mut pos);
        assert_eq!(&pos.0, &[0, 1]);
        assert_eq!(&pos.1, &[1, 1]);
    }
}
<commit_msg>Impl `Zero<BigUint, (BigUint, BigUint)>` for `Pair`<commit_after>use std::marker::PhantomData;

use num::BigUint;

use Construct;
use Data;
use Count;
use Of;
use ToIndex;
use ToPos;
use Zero;

/// Dimension is natural number, position is (min, max).
pub struct Pair<T = Data>(PhantomData<T>);

impl<T> Construct for Pair<T> {
    fn new() -> Pair<T> { Pair(PhantomData) }
}

impl Count<usize> for Pair<Data> {
    type N = usize;
    fn count(&self, dim: &usize) -> usize { dim * (dim - 1) / 2 }
}

impl Count<BigUint> for Pair<Data> {
    type N = BigUint;
    fn count(&self, dim: &BigUint) -> BigUint {
        let _1: BigUint = 1usize.into();
        let _2: BigUint = 2usize.into();
        dim * (dim - _1) / _2
    }
}

impl<T, U> Count<U> for Pair<Of<T>>
    where
        T: Construct + Count<U>,
        Pair: Count<<T as Count<U>>::N, N = <T as Count<U>>::N>
{
    type N = <T as Count<U>>::N;
    fn count(&self, dim: &U) -> Self::N {
        let of: T = Construct::new();
        let data: Pair<Data> = Construct::new();
        data.count(&of.count(dim))
    }
}

impl Zero<usize, (usize, usize)> for Pair<Data> {
    fn zero(&self, _dim: &usize) -> (usize, usize) { (0, 0) }
}

impl Zero<BigUint, (BigUint, BigUint)> for Pair<Data> {
    fn zero(&self, _dim: &BigUint) -> (BigUint, BigUint) { (0usize.into(), 0usize.into()) }
}

impl<T, U, V>
Zero<U, (V, V)> for Pair<Of<T>>
    where T: Construct + Zero<U, V>
{
    fn zero(&self, dim: &U) -> (V, V) {
        let of: T = Construct::new();
        (of.zero(dim), of.zero(dim))
    }
}

impl ToIndex<usize, (usize, usize)>
for Pair<Data> {
    fn to_index(&self, _dim: &usize, &(min, max): &(usize, usize)) -> usize {
        min + max * (max - 1) / 2
    }
}

impl<T, U, V>
ToIndex<U, (V, V)> for Pair<Of<T>>
    where T: Construct + ToIndex<U, V> + Count<U, N = usize>
{
    fn to_index(
        &self,
        dim: &U,
        &(ref min, ref max): &(V, V)
    ) -> usize {
        let of: T = Construct::new();
        let data: Pair<Data> = Construct::new();
        let min = of.to_index(dim, min);
        let max = of.to_index(dim, max);
        data.to_index(&self.count(dim), &(min, max))
    }
}

impl ToPos<usize, (usize, usize)> for Pair<Data> {
    fn to_pos(&self, _dim: &usize, index: usize, pos: &mut (usize, usize)) {
        let max = ((-1f64 + (8f64 * index as f64 + 1f64).sqrt()) / 2f64) as usize + 1;
        let min = index.wrapping_sub(max * (max + 1) / 2).wrapping_add(max);
        *pos = (min, max)
    }
}

impl<T, U, V>
ToPos<U, (V, V)> for Pair<Of<T>>
    where T: Construct + Count<U, N = usize> + ToPos<U, V>
{
    fn to_pos(
        &self,
        dim: &U,
        index: usize,
        &mut (ref mut min, ref mut max): &mut (V, V)
    ) {
        let of: T = Construct::new();
        let data: Pair<Data> = Construct::new();
        let count = of.count(dim);
        let mut pair = (0, 0);
        data.to_pos(&count, index, &mut pair);
        let (pair_min, pair_max) = pair;
        of.to_pos(dim, pair_min, min);
        of.to_pos(dim, pair_max, max);
    }
}

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

    #[test]
    fn features() {
        is_complete::<Pair, usize, (usize, usize)>();
        is_complete::<Pair<Of<Pair>>, usize,
            ((usize, usize), (usize, usize))>();
    }

    #[test]
    fn data() {
        let x: Pair = Construct::new();
        let ref dim = 4;
        assert_eq!(x.count(dim), 6);
        assert_eq!(x.to_index(dim, &(0, 1)), 0);
        assert_eq!(x.to_index(dim, &(0, 2)), 1);
        assert_eq!(x.to_index(dim, &(1, 2)), 2);
        assert_eq!(x.to_index(dim, &(0, 3)), 3);
        let mut new_pos = (0, 0);
        x.to_pos(dim, 3, &mut new_pos);
        assert_eq!(new_pos, (0, 3));
    }

    #[test]
    fn of() {
        let x: Pair<Of<DimensionN>> = Construct::new();
        let ref dim = vec![2, 2];
        assert_eq!(x.count(dim), 6);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 0])), 0);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![0, 1])), 1);
        assert_eq!(x.to_index(dim, &(vec![1, 0], vec![0, 1])), 2);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 1])), 3);
        assert_eq!(x.to_index(dim, &(vec![1, 0], vec![1, 1])), 4);
        assert_eq!(x.to_index(dim, &(vec![0, 1], vec![1, 1])), 5);
        let mut pos = (Vec::new(), Vec::new());
        for i in 0..6 {
            x.to_pos(dim, i, &mut pos);
            // println!("{} {}", &min[], &max[]);
        }
        x.to_pos(dim, 5, &mut pos);
        assert_eq!(&pos.0, &[0, 1]);
        assert_eq!(&pos.1, &[1, 1]);
    }
}
<|endoftext|>


<commit_before>extern mod std;
extern mod zmq;

fn new_server(ctx: zmq::Context, ch: oldcomm::Chan<()>) {
    let socket = result::unwrap(ctx.socket(zmq::REP));
    socket.bind("tcp://127.0.0.1:3456").get();

    let msg = result::unwrap(socket.recv_str(0));
    io::println(fmt!("received %s", msg));

    match socket.send_str(fmt!("hello %s", msg), 0) {
        Ok(()) => { }
        Err(e) => fail e.to_str()
    }

    // Let the main thread know we're done.
    ch.send(());
}

fn new_client(ctx: zmq::Context) {
    io::println("starting client");

    let socket = result::unwrap(ctx.socket(zmq::REQ));

    socket.set_hwm(10u64).get();
    io::println(fmt!("hwm: %?", socket.get_hwm().get()));

    socket.set_identity(str::to_bytes("identity")).get();

    let identity = result::unwrap(socket.get_identity());
    io::println(fmt!("identity: %s", str::from_bytes(identity)));

    io::println("client connecting to server");

    socket.connect("tcp://127.0.0.1:3456").get();
    socket.send_str("foo", 0).get();

    io::println(result::unwrap(socket.recv_str(0)));
}

fn main() {
    let (major, minor, patch) = zmq::version();

    io::println(fmt!("version: %d %d %d", major, minor, patch));

    let ctx = result::unwrap(zmq::init(1));

    // We need to start the server in a separate scheduler as it blocks.
    let po = oldcomm::Port();
    let ch = oldcomm::Chan(&po);
    do task::spawn_sched(task::SingleThreaded) { new_server(ctx, ch) }

    new_client(ctx);

    // Wait for the server to shut down.
    po.recv();

    ctx.term().get();
}
<commit_msg>Update example.rs<commit_after>extern mod std;
extern mod zmq;
use core::comm::{stream, Chan};

fn new_server(ctx: zmq::Context, ch: &Chan<()>) {
    let socket = result::unwrap(ctx.socket(zmq::REP));
    socket.bind("tcp://127.0.0.1:3456").get();

    let msg = result::unwrap(socket.recv_str(0));
    io::println(fmt!("received %s", msg));

    match socket.send_str(fmt!("hello %s", msg), 0) {
        Ok(()) => { },
        Err(e) => fail!(e.to_str())
    }

    // Let the main thread know we're done.
    ch.send(());
}

fn new_client(ctx: zmq::Context) {
    io::println("starting client");

    let socket = result::unwrap(ctx.socket(zmq::REQ));

    socket.set_hwm(10u64).get();
    io::println(fmt!("hwm: %?", socket.get_hwm().get()));

    socket.set_identity(str::to_bytes("identity")).get();

    let identity = result::unwrap(socket.get_identity());
    io::println(fmt!("identity: %s", str::from_bytes(identity)));

    io::println("client connecting to server");

    socket.connect("tcp://127.0.0.1:3456").get();
    socket.send_str("foo", 0).get();

    io::println(result::unwrap(socket.recv_str(0)));
}

fn main() {
    let (major, minor, patch) = zmq::version();

    io::println(fmt!("version: %d %d %d", major, minor, patch));

    let ctx = result::unwrap(zmq::init(1));

    // We need to start the server in a separate scheduler as it blocks.
    let (po, ch) = stream();
    do task::spawn_sched(task::SingleThreaded) { new_server(ctx, &ch) }

    new_client(ctx);

    // Wait for the server to shut down.
    po.recv();

    ctx.term().get();
}
<|endoftext|>


<commit_before>use dicom::core::dicom_value;
use dicom::core::smallvec;
use dicom::{
    core::{DataElement, PrimitiveValue, Tag, VR},
    encoding::transfer_syntax,
    object::{mem::InMemDicomObject, open_file, StandardDataDictionary},
    transfer_syntax::TransferSyntaxRegistry,
};
use dicom_ul::pdu::Pdu;
use dicom_ul::{
    association::ClientAssociationOptions,
    pdu::{PDataValue, PDataValueType},
};
use smallvec::smallvec;
use std::{io::Write, path::PathBuf};
use structopt::StructOpt;
use transfer_syntax::TransferSyntaxIndex;

/// DICOM C-STORE SCU
#[derive(Debug, StructOpt)]
struct App {
    /// socket address to STORE SCP (example: "127.0.0.1:104")
    addr: String,
    /// the DICOM file to store
    file: PathBuf,
    /// verbose mode
    #[structopt(short = "v")]
    verbose: bool,
    /// the C-STORE message ID
    #[structopt(short = "m", long = "message-id", default_value = "1")]
    message_id: u16,
    /// the calling AE title
    #[structopt(long = "calling-ae-title", default_value = "ECHOSCU")]
    calling_ae_title: String,
    /// the called AE title
    #[structopt(long = "called-ae-title", default_value = "ANY-SCP")]
    called_ae_title: String,

    #[structopt(long = "max-pdu-length", default_value = "16384")]
    max_pdu_length: u32,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let App {
        addr,
        file,
        verbose,
        message_id,
        calling_ae_title,
        called_ae_title,
        max_pdu_length,
    } = App::from_args();

    if verbose {
        println!("Opening file '{}'...", file.display());
    }

    let dicom_file = open_file(file)?;

    let meta = dicom_file.meta();

    let storage_sop_class_uid = &meta.media_storage_sop_class_uid;
    let storage_sop_instance_uid = &meta.media_storage_sop_instance_uid;
    let transfer_syntax = &meta.transfer_syntax;

    if verbose {
        println!("Establishing association with '{}'...", &addr);
    }

    let mut scu = ClientAssociationOptions::new()
        .with_abstract_syntax(storage_sop_class_uid.to_string())
        .with_transfer_syntax(transfer_syntax.to_string())
        .calling_ae_title(calling_ae_title)
        .called_ae_title(called_ae_title)
        .max_pdu_length(max_pdu_length)
        .establish(addr)?;

    if verbose {
        println!("Association established");
    }
    let ts = TransferSyntaxRegistry
        .get(&transfer_syntax)
        .expect("Poorly negotiated transfer syntax");

    if verbose {
        println!("Transfer Syntax: {}", ts.name());
    }

    let cmd = store_req_command(
        &storage_sop_class_uid,
        &storage_sop_instance_uid,
        message_id,
    );

    let mut cmd_data = Vec::with_capacity(128);
    cmd.write_dataset_with_ts(
        &mut cmd_data,
        &dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased(),
    )?;

    // !!! ensure that the negotiated transfer syntax is used

    let mut object_data = Vec::with_capacity(1024);
    dicom_file.write_dataset_with_ts(&mut object_data, &ts)?;

    let nbytes = cmd_data.len() + object_data.len();

    if verbose {
        println!("Sending payload (~ {} Kb)...", nbytes / 1024);
    }

    let pc_selected = scu.presentation_contexts()
        .first()
        .ok_or("No presentation context accepted")?
        .clone();

    if nbytes < max_pdu_length as usize - 100 {
        let pdu = Pdu::PData {
            data: vec![
                PDataValue {
                    presentation_context_id: pc_selected.id,
                    value_type: PDataValueType::Command,
                    is_last: true,
                    data: cmd_data,
                },
                PDataValue {
                    presentation_context_id: pc_selected.id,
                    value_type: PDataValueType::Data,
                    is_last: true,
                    data: object_data,
                },
            ],
        };

        scu.send(&pdu)?;
    } else {
        let pdu = Pdu::PData {
            data: vec![PDataValue {
                presentation_context_id: pc_selected.id,
                value_type: PDataValueType::Command,
                is_last: true,
                data: cmd_data,
            }],
        };

        scu.send(&pdu)?;

        scu.send_pdata(pc_selected.id)
            .write_all(&object_data)?;
    }

    if verbose {
        println!("Awaiting response...");
    }

    let rsp_pdu = scu.receive()?;

    match rsp_pdu {
        Pdu::PData { data } => {
            let data_value = &data[0];

            let cmd_obj = InMemDicomObject::read_dataset_with_ts(
                &data_value.data[..],
                &dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased(),
            )?;
            if verbose {
                println!("Response: {:?}", cmd_obj);
            }
            let status = cmd_obj.element(Tag(0x0000, 0x0900))?.to_int::<u16>()?;
            if status == 0 {
                println!("Sucessfully stored instance `{}`", storage_sop_instance_uid);
            } else {
                println!(
                    "Failed to store instance '{}' (status code {})",
                    storage_sop_instance_uid, status
                );
            }

            scu.release()?;
        }

        pdu @ Pdu::Unknown { .. }
        | pdu @ Pdu::AssociationRQ { .. }
        | pdu @ Pdu::AssociationAC { .. }
        | pdu @ Pdu::AssociationRJ { .. }
        | pdu @ Pdu::ReleaseRQ
        | pdu @ Pdu::ReleaseRP
        | pdu @ Pdu::AbortRQ { .. } => {
            eprintln!("Unexpected SCP response: {:?}", pdu);
            std::process::exit(-2);
        }
    }

    Ok(())
}

fn store_req_command(
    storage_sop_class_uid: &str,
    storage_sop_instance_uid: &str,
    message_id: u16,
) -> InMemDicomObject<StandardDataDictionary> {
    let mut obj = InMemDicomObject::create_empty();

    // group length
    obj.put(DataElement::new(
        Tag(0x0000, 0x0000),
        VR::UL,
        PrimitiveValue::from(0),
    ));

    // SOP Class UID
    obj.put(DataElement::new(
        Tag(0x0000, 0x0002),
        VR::UI,
        dicom_value!(Str, storage_sop_class_uid),
    ));

    // command field
    obj.put(DataElement::new(
        Tag(0x0000, 0x0100),
        VR::US,
        dicom_value!(U16, [0x0001]),
    ));

    // message ID
    obj.put(DataElement::new(
        Tag(0x0000, 0x0110),
        VR::US,
        dicom_value!(U16, [message_id]),
    ));

    //priority
    obj.put(DataElement::new(
        Tag(0x0000, 0x0700),
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));

    // data set type
    obj.put(DataElement::new(
        Tag(0x0000, 0x0800),
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));

    // affected SOP Instance UID
    obj.put(DataElement::new(
        Tag(0x0000, 0x1000),
        VR::UI,
        dicom_value!(Str, storage_sop_instance_uid),
    ));

    obj
}
<commit_msg>[storescu] document max_pdu_length arg<commit_after>use dicom::core::dicom_value;
use dicom::core::smallvec;
use dicom::{
    core::{DataElement, PrimitiveValue, Tag, VR},
    encoding::transfer_syntax,
    object::{mem::InMemDicomObject, open_file, StandardDataDictionary},
    transfer_syntax::TransferSyntaxRegistry,
};
use dicom_ul::pdu::Pdu;
use dicom_ul::{
    association::ClientAssociationOptions,
    pdu::{PDataValue, PDataValueType},
};
use smallvec::smallvec;
use std::{io::Write, path::PathBuf};
use structopt::StructOpt;
use transfer_syntax::TransferSyntaxIndex;

/// DICOM C-STORE SCU
#[derive(Debug, StructOpt)]
struct App {
    /// socket address to STORE SCP (example: "127.0.0.1:104")
    addr: String,
    /// the DICOM file to store
    file: PathBuf,
    /// verbose mode
    #[structopt(short = "v")]
    verbose: bool,
    /// the C-STORE message ID
    #[structopt(short = "m", long = "message-id", default_value = "1")]
    message_id: u16,
    /// the calling AE title
    #[structopt(long = "calling-ae-title", default_value = "ECHOSCU")]
    calling_ae_title: String,
    /// the called AE title
    #[structopt(long = "called-ae-title", default_value = "ANY-SCP")]
    called_ae_title: String,
    /// the maximum PDU length
    #[structopt(long = "max-pdu-length", default_value = "16384")]
    max_pdu_length: u32,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let App {
        addr,
        file,
        verbose,
        message_id,
        calling_ae_title,
        called_ae_title,
        max_pdu_length,
    } = App::from_args();

    if verbose {
        println!("Opening file '{}'...", file.display());
    }

    let dicom_file = open_file(file)?;

    let meta = dicom_file.meta();

    let storage_sop_class_uid = &meta.media_storage_sop_class_uid;
    let storage_sop_instance_uid = &meta.media_storage_sop_instance_uid;
    let transfer_syntax = &meta.transfer_syntax;

    if verbose {
        println!("Establishing association with '{}'...", &addr);
    }

    let mut scu = ClientAssociationOptions::new()
        .with_abstract_syntax(storage_sop_class_uid.to_string())
        .with_transfer_syntax(transfer_syntax.to_string())
        .calling_ae_title(calling_ae_title)
        .called_ae_title(called_ae_title)
        .max_pdu_length(max_pdu_length)
        .establish(addr)?;

    if verbose {
        println!("Association established");
    }
    let ts = TransferSyntaxRegistry
        .get(&transfer_syntax)
        .expect("Poorly negotiated transfer syntax");

    if verbose {
        println!("Transfer Syntax: {}", ts.name());
    }

    let cmd = store_req_command(
        &storage_sop_class_uid,
        &storage_sop_instance_uid,
        message_id,
    );

    let mut cmd_data = Vec::with_capacity(128);
    cmd.write_dataset_with_ts(
        &mut cmd_data,
        &dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased(),
    )?;

    // !!! ensure that the negotiated transfer syntax is used

    let mut object_data = Vec::with_capacity(1024);
    dicom_file.write_dataset_with_ts(&mut object_data, &ts)?;

    let nbytes = cmd_data.len() + object_data.len();

    if verbose {
        println!("Sending payload (~ {} Kb)...", nbytes / 1024);
    }

    let pc_selected = scu.presentation_contexts()
        .first()
        .ok_or("No presentation context accepted")?
        .clone();

    if nbytes < max_pdu_length as usize - 100 {
        let pdu = Pdu::PData {
            data: vec![
                PDataValue {
                    presentation_context_id: pc_selected.id,
                    value_type: PDataValueType::Command,
                    is_last: true,
                    data: cmd_data,
                },
                PDataValue {
                    presentation_context_id: pc_selected.id,
                    value_type: PDataValueType::Data,
                    is_last: true,
                    data: object_data,
                },
            ],
        };

        scu.send(&pdu)?;
    } else {
        let pdu = Pdu::PData {
            data: vec![PDataValue {
                presentation_context_id: pc_selected.id,
                value_type: PDataValueType::Command,
                is_last: true,
                data: cmd_data,
            }],
        };

        scu.send(&pdu)?;

        scu.send_pdata(pc_selected.id)
            .write_all(&object_data)?;
    }

    if verbose {
        println!("Awaiting response...");
    }

    let rsp_pdu = scu.receive()?;

    match rsp_pdu {
        Pdu::PData { data } => {
            let data_value = &data[0];

            let cmd_obj = InMemDicomObject::read_dataset_with_ts(
                &data_value.data[..],
                &dicom::transfer_syntax::entries::IMPLICIT_VR_LITTLE_ENDIAN.erased(),
            )?;
            if verbose {
                println!("Response: {:?}", cmd_obj);
            }
            let status = cmd_obj.element(Tag(0x0000, 0x0900))?.to_int::<u16>()?;
            if status == 0 {
                println!("Sucessfully stored instance `{}`", storage_sop_instance_uid);
            } else {
                println!(
                    "Failed to store instance '{}' (status code {})",
                    storage_sop_instance_uid, status
                );
            }

            scu.release()?;
        }

        pdu @ Pdu::Unknown { .. }
        | pdu @ Pdu::AssociationRQ { .. }
        | pdu @ Pdu::AssociationAC { .. }
        | pdu @ Pdu::AssociationRJ { .. }
        | pdu @ Pdu::ReleaseRQ
        | pdu @ Pdu::ReleaseRP
        | pdu @ Pdu::AbortRQ { .. } => {
            eprintln!("Unexpected SCP response: {:?}", pdu);
            std::process::exit(-2);
        }
    }

    Ok(())
}

fn store_req_command(
    storage_sop_class_uid: &str,
    storage_sop_instance_uid: &str,
    message_id: u16,
) -> InMemDicomObject<StandardDataDictionary> {
    let mut obj = InMemDicomObject::create_empty();

    // group length
    obj.put(DataElement::new(
        Tag(0x0000, 0x0000),
        VR::UL,
        PrimitiveValue::from(0),
    ));

    // SOP Class UID
    obj.put(DataElement::new(
        Tag(0x0000, 0x0002),
        VR::UI,
        dicom_value!(Str, storage_sop_class_uid),
    ));

    // command field
    obj.put(DataElement::new(
        Tag(0x0000, 0x0100),
        VR::US,
        dicom_value!(U16, [0x0001]),
    ));

    // message ID
    obj.put(DataElement::new(
        Tag(0x0000, 0x0110),
        VR::US,
        dicom_value!(U16, [message_id]),
    ));

    //priority
    obj.put(DataElement::new(
        Tag(0x0000, 0x0700),
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));

    // data set type
    obj.put(DataElement::new(
        Tag(0x0000, 0x0800),
        VR::US,
        dicom_value!(U16, [0x0000]),
    ));

    // affected SOP Instance UID
    obj.put(DataElement::new(
        Tag(0x0000, 0x1000),
        VR::UI,
        dicom_value!(Str, storage_sop_instance_uid),
    ));

    obj
}
<|endoftext|>


<commit_before>//!A raytracer.
#![feature(path, io)]
extern crate image;
extern crate rand;

use std::old_io::File;
use std::num::Float;
use std::f32::consts::PI_2;

use rand::distributions::IndependentSample;

use point::Point3;
use vec::Vec3;

mod vec;
mod point;

const EPS: f32 = 0.00005;

#[derive(Copy)]
struct Ray3 {
    start: Point3,
    dir: Vec3
}

struct Intersection {
    time: f32,
    point: Point3,
    normal: Vec3
}

trait Scene {
    fn intersect(&self, ray: Ray3) -> Option<Intersection>;
}

struct Sphere {
    center: Point3,
    radius: f32
}

impl Scene for Sphere {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        let offset = ray.start - self.center;

        let a = ray.dir.mag2();
        let b = 2. * offset.dot(ray.dir);
        let c = offset.mag2() - self.radius*self.radius;

        let descrim = b*b - 4.*a*c;
        if descrim > 0. {
            let t1 = (-b - descrim.sqrt()) / (2. * a);
            let t2 = (-b + descrim.sqrt()) / (2. * a);
            if t1 > EPS {
                let p = ray.start + ray.dir * t1;
                let normal = p - self.center;
                Some(Intersection {
                    time: t1,
                    point: p,
                    normal: normal
                })
            } else if t2 > EPS {
                let p = ray.start + ray.dir * t2;
                let normal = p - self.center;
                Some(Intersection {
                    time: t2,
                    point: p,
                    normal: normal
                })
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct Plane {
    origin: Point3,
    normal: Vec3
}

impl Scene for Plane {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        let divisor = ray.dir.dot(self.normal);
        if divisor == 0. {
            None
        } else {
            let offset = ray.start - self.origin;
            let time = -offset.dot(self.normal) / divisor;
            if time > EPS {
                Some(Intersection {
                    time: time,
                    point: ray.start + ray.dir * time,
                    normal: self.normal
                })
            } else {
                None
            }
        }
    }
}

impl<A: Scene, B: Scene> Scene for (A, B) {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        match self.0.intersect(ray) {
            Some(ai) => {
                match self.1.intersect(ray) {
                    Some(bi) => if ai.time < bi.time {
                        Some(ai)
                    } else {
                        Some(bi)
                    },
                    None => Some(ai)
                }
            },
            None => self.1.intersect(ray)
        }
    }
}

fn clamp(val: f32) -> f32 {
    if val > 1. {
        1.
    } else if val < 0. {
        0.
    } else {
        val
    }
}

fn rand_sphere<R: rand::Rng>(rng: &mut R) -> Vec3 {
    let z = rand::distributions::Range::new(-1., 1.).ind_sample(rng);
    let r = (1. - z*z).sqrt();
    let angle = rand::distributions::Range::new(0., PI_2).ind_sample(rng);
    Vec3::new(r*angle.cos(), r*angle.sin(), z)
}

fn main() {
    let mut rng = rand::thread_rng();

    let num_bounces = 10;
    let rays_per_pixel = 10;
    let scene = (
        (Sphere {
            center: Point3::new(1.2, 0.0, 5.0),
            radius: 0.3
        },
        Sphere {
            center: Point3::new(1.5, 0.0, 3.5),
            radius: 0.35
        }),
        (Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(2.0, 0.0, -1.0)
        },
        Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(-1.0, 0.0, -2.0)
        })
    );
    let light = Point3::new(1.0, -1.5, 0.5);

    let imgx = 800;
    let imgy = 800;

    let scalex = 4.0 / imgx as f32;
    let scaley = 4.0 / imgy as f32;

    // Create a new ImgBuf with width: imgx and height: imgy
    let mut imgbuf = image::ImageBuffer::new(imgx, imgy);

    // Iterate over the coordiantes and pixels of the image
    for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
        let cy = -(y as f32 * scaley - 2.0);
        let cx = x as f32 * scalex - 2.0;

        let mut total_light = 0.;
        for _ in 0..rays_per_pixel {
            let mut ray = Ray3 {
                start: Point3::new(0., 0., -8.0),
                dir: Vec3::new(cx, cy, 8.0)
            };
            let mut strength = 1.;
            for _ in 0..num_bounces {
                if let Some(intersection) = scene.intersect(ray) {
                    let light_ray = Ray3 {
                        start: intersection.point,
                        dir: light - intersection.point
                    };

                    let can_see_light = match scene.intersect(light_ray) {
                        Some(light_intersection) => {
                            light_intersection.time > 1.
                        },
                        None => true
                    };

                    if can_see_light {
                        let light_strength = 10.0 / light_ray.dir.mag2();
                        let scale = (intersection.normal.mag2() * light_ray.dir.mag2()).sqrt();
                        total_light += strength * light_strength * intersection.normal.dot(light_ray.dir) / scale;
                    }

                    let cand_dir = rand_sphere(&mut rng);
                    let dir = if cand_dir.dot(intersection.normal) < 0. {
                        -cand_dir
                    } else {
                        cand_dir
                    };
                    ray = Ray3 {
                        start: intersection.point,
                        dir: dir
                    };
                    strength *= dir.dot(intersection.normal) / intersection.normal.mag2().sqrt();
                } else {
                    break;
                }
            }
        }

        // Create an 8bit pixel of type Luma and value i
        // and assign in to the pixel at position (x, y)
        *pixel = image::Luma([(clamp(total_light / rays_per_pixel as f32)*255.) as u8]);
    }

    // Save the image as “out.png”
    let ref mut fout = File::create(&Path::new("out.png")).unwrap();

    // We must indicate the image’s color type and what format to save as
    let _ = image::ImageLuma8(imgbuf).save(fout, image::PNG);
}
<commit_msg>Get rid of weird artifacts by doing slightly better than an epsilon<commit_after>//!A raytracer.
#![feature(path, io)]
extern crate image;
extern crate rand;

use std::old_io::File;
use std::num::Float;
use std::f32::consts::PI_2;

use rand::distributions::IndependentSample;

use point::Point3;
use vec::Vec3;

mod vec;
mod point;

// TODO: Improve edges
const EPS: f32 = 0.00005;

#[derive(Copy)]
struct Ray3 {
    start: Point3,
    dir: Vec3
}

struct Intersection {
    time: f32,
    point: Point3,
    normal: Vec3
}

trait Scene {
    fn intersect(&self, ray: Ray3) -> Option<Intersection>;
}

struct Sphere {
    center: Point3,
    radius: f32
}

impl Scene for Sphere {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        let offset = ray.start - self.center;
        // TODO: Improve edges
        if offset.mag2() < self.radius*self.radius {
            return None;
        }

        let a = ray.dir.mag2();
        let b = 2. * offset.dot(ray.dir);
        let c = offset.mag2() - self.radius*self.radius;

        let descrim = b*b - 4.*a*c;
        if descrim > 0. {
            let t1 = (-b - descrim.sqrt()) / (2. * a);
            let t2 = (-b + descrim.sqrt()) / (2. * a);
            if t1 > EPS {
                let p = ray.start + ray.dir * t1;
                let normal = p - self.center;
                Some(Intersection {
                    time: t1,
                    point: p,
                    normal: normal
                })
            } else if t2 > EPS {
                let p = ray.start + ray.dir * t2;
                let normal = p - self.center;
                Some(Intersection {
                    time: t2,
                    point: p,
                    normal: normal
                })
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct Plane {
    origin: Point3,
    normal: Vec3
}

impl Scene for Plane {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        let divisor = ray.dir.dot(self.normal);
        if divisor == 0. {
            None
        } else {
            let offset = ray.start - self.origin;
            let time = -offset.dot(self.normal) / divisor;
            if time > EPS {
                Some(Intersection {
                    time: time,
                    point: ray.start + ray.dir * time,
                    normal: self.normal
                })
            } else {
                None
            }
        }
    }
}

impl<A: Scene, B: Scene> Scene for (A, B) {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        match self.0.intersect(ray) {
            Some(ai) => {
                match self.1.intersect(ray) {
                    Some(bi) => if ai.time < bi.time {
                        Some(ai)
                    } else {
                        Some(bi)
                    },
                    None => Some(ai)
                }
            },
            None => self.1.intersect(ray)
        }
    }
}

fn clamp(val: f32) -> f32 {
    if val > 1. {
        1.
    } else if val < 0. {
        0.
    } else {
        val
    }
}

fn rand_sphere<R: rand::Rng>(rng: &mut R) -> Vec3 {
    let z = rand::distributions::Range::new(-1., 1.).ind_sample(rng);
    let r = (1. - z*z).sqrt();
    let angle = rand::distributions::Range::new(0., PI_2).ind_sample(rng);
    Vec3::new(r*angle.cos(), r*angle.sin(), z)
}

fn main() {
    let mut rng = rand::thread_rng();

    let num_bounces = 10;
    let rays_per_pixel = 50;
    let scene = (
        (Sphere {
            center: Point3::new(1.2, 0.0, 5.0),
            radius: 0.3
        },
        Sphere {
            center: Point3::new(1.5, 0.0, 3.5),
            radius: 0.35
        }),
        (Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(2.0, 0.0, -1.0)
        },
        Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(-1.0, 0.0, -2.0)
        })
    );
    let light = Point3::new(1.0, -1.5, 0.5);

    let imgx = 800;
    let imgy = 800;

    let scalex = 4.0 / imgx as f32;
    let scaley = 4.0 / imgy as f32;

    // Create a new ImgBuf with width: imgx and height: imgy
    let mut imgbuf = image::ImageBuffer::new(imgx, imgy);

    // Iterate over the coordiantes and pixels of the image
    for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
        let cy = -(y as f32 * scaley - 2.0);
        let cx = x as f32 * scalex - 2.0;

        let mut total_light = 0.;
        for _ in 0..rays_per_pixel {
            let mut ray = Ray3 {
                start: Point3::new(0., 0., -8.0),
                dir: Vec3::new(cx, cy, 8.0)
            };
            let mut strength = 1.;
            for _ in 0..num_bounces {
                if let Some(intersection) = scene.intersect(ray) {
                    let light_ray = Ray3 {
                        start: intersection.point,
                        dir: light - intersection.point
                    };

                    let can_see_light = match scene.intersect(light_ray) {
                        Some(light_intersection) => {
                            light_intersection.time > 1.
                        },
                        None => true
                    };

                    if can_see_light {
                        let light_strength = 10.0 / light_ray.dir.mag2();
                        let scale = (intersection.normal.mag2() * light_ray.dir.mag2()).sqrt();
                        total_light += strength * light_strength * intersection.normal.dot(light_ray.dir) / scale;
                    }

                    let cand_dir = rand_sphere(&mut rng);
                    let dir = if cand_dir.dot(intersection.normal) < 0. {
                        -cand_dir
                    } else {
                        cand_dir
                    };
                    ray = Ray3 {
                        start: intersection.point,
                        dir: dir
                    };
                    strength *= dir.dot(intersection.normal) / intersection.normal.mag2().sqrt();
                } else {
                    break;
                }
            }
        }

        // Create an 8bit pixel of type Luma and value i
        // and assign in to the pixel at position (x, y)
        *pixel = image::Luma([(clamp(total_light / rays_per_pixel as f32)*255.) as u8]);
    }

    // Save the image as “out.png”
    let ref mut fout = File::create(&Path::new("out.png")).unwrap();

    // We must indicate the image’s color type and what format to save as
    let _ = image::ImageLuma8(imgbuf).save(fout, image::PNG);
}
<|endoftext|>


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

#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "alloc_jemalloc"]
#![crate_type = "rlib"]
#![staged_api]
#![no_std]
#![cfg_attr(not(stage0), allocator)]
#![unstable(feature = "alloc_jemalloc",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "27783")]
#![feature(allocator)]
#![feature(libc)]
#![feature(no_std)]
#![feature(staged_api)]

extern crate libc;

use libc::{c_int, c_void, size_t};

// Linkage directives to pull in jemalloc and its dependencies.
//
// On some platforms we need to be sure to link in `pthread` which jemalloc
// depends on, and specifically on android we need to also link to libgcc.
// Currently jemalloc is compiled with gcc which will generate calls to
// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
// libcompiler-rt), so link that in to get that support.
#[link(name = "jemalloc", kind = "static")]
#[cfg_attr(target_os = "android", link(name = "gcc"))]
#[cfg_attr(all(not(windows),
               not(target_os = "android"),
               not(target_env = "musl")),
           link(name = "pthread"))]
extern {
    fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void;
    fn je_rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
    fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t,
                  flags: c_int) -> size_t;
    fn je_sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
    fn je_nallocx(size: size_t, flags: c_int) -> size_t;
}

// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(any(target_arch = "arm",
              target_arch = "mips",
              target_arch = "mipsel",
              target_arch = "powerpc")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86",
              target_arch = "x86_64",
              target_arch = "aarch64")))]
const MIN_ALIGN: usize = 16;

// MALLOCX_ALIGN(a) macro
fn mallocx_align(a: usize) -> c_int { a.trailing_zeros() as c_int }

fn align_to_flags(align: usize) -> c_int {
    if align <= MIN_ALIGN { 0 } else { mallocx_align(align) }
}

#[no_mangle]
pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    let flags = align_to_flags(align);
    unsafe { je_mallocx(size as size_t, flags) as *mut u8 }
}

#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize,
                                align: usize) -> *mut u8 {
    let flags = align_to_flags(align);
    unsafe { je_rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
}

#[no_mangle]
pub extern fn __rust_reallocate_inplace(ptr: *mut u8, _old_size: usize,
                                        size: usize, align: usize) -> usize {
    let flags = align_to_flags(align);
    unsafe { je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
}

#[no_mangle]
pub extern fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
    let flags = align_to_flags(align);
    unsafe { je_sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
}

#[no_mangle]
pub extern fn __rust_usable_size(size: usize, align: usize) -> usize {
    let flags = align_to_flags(align);
    unsafe { je_nallocx(size as size_t, flags) as usize }
}
<commit_msg>Rollup merge of #28988 - ahmedcharles:liballoc_jemalloc, r=nrc<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "alloc_jemalloc"]
#![crate_type = "rlib"]
#![staged_api]
#![no_std]
#![cfg_attr(not(stage0), allocator)]
#![unstable(feature = "alloc_jemalloc",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name",
            issue = "27783")]
#![feature(allocator)]
#![feature(libc)]
#![feature(no_std)]
#![feature(staged_api)]

extern crate libc;

use libc::{c_int, c_void, size_t};

// Linkage directives to pull in jemalloc and its dependencies.
//
// On some platforms we need to be sure to link in `pthread` which jemalloc
// depends on, and specifically on android we need to also link to libgcc.
// Currently jemalloc is compiled with gcc which will generate calls to
// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
// libcompiler-rt), so link that in to get that support.
#[link(name = "jemalloc", kind = "static")]
#[cfg_attr(target_os = "android", link(name = "gcc"))]
#[cfg_attr(all(not(windows),
               not(target_os = "android"),
               not(target_env = "musl")),
           link(name = "pthread"))]
extern {
    fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void;
    fn je_rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
    fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
    fn je_sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
    fn je_nallocx(size: size_t, flags: c_int) -> size_t;
}

// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(any(target_arch = "arm",
              target_arch = "mips",
              target_arch = "mipsel",
              target_arch = "powerpc")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86",
              target_arch = "x86_64",
              target_arch = "aarch64")))]
const MIN_ALIGN: usize = 16;

// MALLOCX_ALIGN(a) macro
fn mallocx_align(a: usize) -> c_int {
    a.trailing_zeros() as c_int
}

fn align_to_flags(align: usize) -> c_int {
    if align <= MIN_ALIGN {
        0
    } else {
        mallocx_align(align)
    }
}

#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    let flags = align_to_flags(align);
    unsafe { je_mallocx(size as size_t, flags) as *mut u8 }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
                                    _old_size: usize,
                                    size: usize,
                                    align: usize)
                                    -> *mut u8 {
    let flags = align_to_flags(align);
    unsafe { je_rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
                                            _old_size: usize,
                                            size: usize,
                                            align: usize)
                                            -> usize {
    let flags = align_to_flags(align);
    unsafe { je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
}

#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
    let flags = align_to_flags(align);
    unsafe { je_sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
}

#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
    let flags = align_to_flags(align);
    unsafe { je_nallocx(size as size_t, flags) as usize }
}
<|endoftext|>