<commit_before>use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;
use ast::*;
use test::Bencher;

#[derive(Clone, PartialEq)]
pub struct Env {
    pub table: HashMap<String, Expr>,
    pub parent: Option<Rc<RefCell<Env>>>
}

#[allow(unreachable_code)]
#[allow(dead_code)]
impl Env {
    pub fn new() -> Env {
        let mut res = Env {
            table: HashMap::new(),
            parent: None
        };
        res.setup();
        res
    }

    pub fn def_var(&mut self, var: String, val: Expr) {
        self.add_binding(var, val);
    }

    pub fn str_def(&mut self, var: &str, val: Expr) {
        self.add_binding(var.to_string(), val);
    }

    pub fn add_binding(&mut self, var: String, val: Expr) {
        self.table.insert(var, val);
    }

    pub fn lookup(&self, var: String) -> Option<Expr> {
        match self.table.get(&var) {
            Some(val) => return Some(val.clone()),
            _ => {}
        }
        match self.parent.clone() {
            Some(p) =>
                return p.borrow().lookup(var),
            _ => {
                return None;
            }
        };
    }

    pub fn str_lookup(&self, var: &str) -> Option<Expr> {
        self.lookup(var.to_string())
    }

    pub fn parent(&self) ->  Option<Rc<RefCell<Env>>> {
        match self.parent.clone() {
            Some(p) => return Some(p.clone()),
            _ => { return None; }
        }
    }

    pub fn extend(&mut self, vars: Expr, vals: Expr) -> Rc<RefCell<Env>> {
        let mut _vars = vars;
        let mut _vals = vals;
        let mut res = Env {
            table: HashMap::new(),
            parent: Some(Rc::new(RefCell::new(self.clone())))
        };
        loop {
            if _vars.is_last() { break; }
            res.add_binding(_vars.car().as_str(), _vals.car());
            _vars = _vars.cdr();
            _vals = _vals.cdr();
        }
        res.add_binding(_vars.car().as_str(), _vals.car());
        return Rc::new(RefCell::new(res));
    }

    fn setup(&mut self) {
        macro_rules! def_proc {
            ($func_name:ident, $raw_func_name:ident) => (
                fn $func_name(args: Expr) -> Expr {
                    Expr::Bool(BoolNode::new(args.car().$raw_func_name()))
                }
                )
        }

        macro_rules! add_proc {
            ($type_str:expr, $func_name:ident) => (
                self.def_var($type_str.to_string(),
                             Expr::Proc(ProcNode::new($func_name)))
                    )
        }

        def_proc!(is_null, is_empty);
        def_proc!(is_boolean, is_bool);
        def_proc!(is_symbol, is_symbol);
        def_proc!(is_string, is_string);
        def_proc!(is_pair, is_pair);
        def_proc!(is_char, is_char);
        def_proc!(is_int, is_int);

        add_proc!("null?", is_null);
        add_proc!("boolean?", is_boolean);
        add_proc!("symbol?", is_symbol);
        add_proc!("string?", is_string);
        add_proc!("char?", is_char);
        add_proc!("integer?", is_int);
        add_proc!("+", add);
        add_proc!("-", sub);
        add_proc!("*", mul);
        add_proc!("/", div);
        add_proc!("eq?", eq);
        add_proc!("=", eq);
        add_proc!("<", less);
        add_proc!(">", large);
        add_proc!("pair?", is_pair);
        add_proc!("car", car);
        add_proc!("cdr", cdr);
        add_proc!("cons", cons);
    }
}

fn add(args: Expr) -> Expr {
    let mut res = 0is;
    let mut exps = args;
    loop {
        if exps.is_empty() { break; }
        res += exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn sub(args: Expr) -> Expr {
    let mut res = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        res -= exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn mul(args: Expr) -> Expr {
    let mut res = 1is;
    let mut exps = args;
    loop {
        if exps.is_empty() { break; }
        res *= exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn div(args: Expr) -> Expr {
    let mut exps = args;
    let mut res = exps.car().as_int();
    exps = exps.cdr();
    loop {
        if exps.is_empty() { break; }
        let nxt = exps.car().as_int();
        if nxt == 0 {
            return Expr::Symbol(SymbolNode::new("Fail"));
        }
        res /= nxt;
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn cons(args: Expr) -> Expr {
    let obj1 = args.car();
    let obj2 = args.c("da");
    Expr::Pair(PairNode::new(obj1, Expr::Pair(PairNode::new(obj2, Expr::Nil))))
}

fn eq(args: Expr) -> Expr {
    let obj1 = args.car();
    let obj2 = args.c("da");
    Expr::Bool(BoolNode::new(obj1 == obj2))
}

fn less(args: Expr) -> Expr {
    let val = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        if val >= exps.car().as_int() {
            return Expr::Bool(BoolNode::new(false));
        }
        exps = exps.cdr();
    }
    Expr::Bool(BoolNode::new(true))
}

fn car(args: Expr) -> Expr {
    assert!(args.car().is_pair());
    args.c("aa")
}

fn cdr(args: Expr) -> Expr {
    assert!(args.car().is_pair());
    args.c("ad")
}

fn large(args: Expr) -> Expr {
    let val = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        if val <= exps.car().as_int() {
            return Expr::Bool(BoolNode::new(false));
        }
        exps = exps.cdr();
    }
    Expr::Bool(BoolNode::new(true))
}

#[test]
fn test_env() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let val = env.str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");

    env.str_def("1", Expr::Int(IntNode::new(1)));
    let val = env.str_lookup("1");
    assert!(val.unwrap().as_int() == 1);

    env.str_def("1", Expr::Int(IntNode::new(2)));
    let val = env.str_lookup("1");
    assert!(val.unwrap().as_int() == 2);

    env.str_def("sym", Expr::Int(IntNode::new(2)));
    let val = env.str_lookup("sym");
    assert!(val.unwrap().as_int() == 2);

    let val = env.str_lookup("null?");
    assert!(val.unwrap().is_proc());
    let val = env.str_lookup("char?");
    assert!(val.unwrap().is_proc());
    let val = env.str_lookup("integer?");
    assert!(val.unwrap().is_proc());

    let val = env.str_lookup(">");
    assert!(val.unwrap().is_proc());

    let val = env.str_lookup("<");
    assert!(val.unwrap().is_proc());

}

#[test]
fn test_env_extend() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val")), Expr::Nil));

    let extend_env = env.extend(vars, vals);
    let val = extend_env.clone().borrow_mut().str_lookup("var");
    assert!(val.unwrap().as_str() == "val");

    let val = extend_env.clone().borrow_mut().str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var_x")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val_x")), Expr::Nil));

    let extend_env = extend_env.clone().borrow_mut().extend(vars, vals);
    let val = extend_env.clone().borrow_mut().str_lookup("var_x");
    assert!(val.unwrap().as_str() == "val_x");

    extend_env.clone().borrow_mut().str_def("1", Expr::Str(StrNode::new("1")));

    let val = extend_env.clone().borrow_mut().str_lookup("1");
    assert!(val.unwrap().as_str() == "1");
}

#[test]
fn test_env_parent() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val")), Expr::Nil));

    let extend_env = env.extend(vars, vals);
    let parent = extend_env.clone().borrow_mut().parent().unwrap();
    let val = parent.clone().borrow_mut().str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");
}

#[bench]
fn env_bench(b: &mut Bencher) {
    fn test_env() {
        let mut env = Env::new();
        for i in 1..1000 {
            let key = i.to_string();
            env.def_var(key.clone(), Expr::Str(StrNode::new("world")));
            let val = env.lookup(key);
            assert!(val.unwrap().as_str() == "world");
        }
    }

    b.iter(|| test_env());
}
<commit_msg>more bench<commit_after>use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;
use ast::*;
use test::Bencher;

#[derive(Clone, PartialEq)]
pub struct Env {
    pub table: HashMap<String, Expr>,
    pub parent: Option<Rc<RefCell<Env>>>
}

#[allow(unreachable_code)]
#[allow(dead_code)]
impl Env {
    pub fn new() -> Env {
        let mut res = Env {
            table: HashMap::new(),
            parent: None
        };
        res.setup();
        res
    }

    pub fn def_var(&mut self, var: String, val: Expr) {
        self.add_binding(var, val);
    }

    pub fn str_def(&mut self, var: &str, val: Expr) {
        self.add_binding(var.to_string(), val);
    }

    pub fn add_binding(&mut self, var: String, val: Expr) {
        self.table.insert(var, val);
    }

    pub fn lookup(&self, var: String) -> Option<Expr> {
        match self.table.get(&var) {
            Some(val) => return Some(val.clone()),
            _ => {}
        }
        match self.parent.clone() {
            Some(p) =>
                return p.borrow().lookup(var),
            _ => {
                return None;
            }
        };
    }

    pub fn str_lookup(&self, var: &str) -> Option<Expr> {
        self.lookup(var.to_string())
    }

    pub fn parent(&self) ->  Option<Rc<RefCell<Env>>> {
        match self.parent.clone() {
            Some(p) => return Some(p.clone()),
            _ => { return None; }
        }
    }

    pub fn extend(&mut self, vars: Expr, vals: Expr) -> Rc<RefCell<Env>> {
        let mut _vars = vars;
        let mut _vals = vals;
        let mut res = Env {
            table: HashMap::new(),
            parent: Some(Rc::new(RefCell::new(self.clone())))
        };
        loop {
            if _vars.is_last() { break; }
            res.add_binding(_vars.car().as_str(), _vals.car());
            _vars = _vars.cdr();
            _vals = _vals.cdr();
        }
        res.add_binding(_vars.car().as_str(), _vals.car());
        return Rc::new(RefCell::new(res));
    }

    fn setup(&mut self) {
        macro_rules! def_proc {
            ($func_name:ident, $raw_func_name:ident) => (
                fn $func_name(args: Expr) -> Expr {
                    Expr::Bool(BoolNode::new(args.car().$raw_func_name()))
                }
                )
        }

        macro_rules! add_proc {
            ($type_str:expr, $func_name:ident) => (
                self.def_var($type_str.to_string(),
                             Expr::Proc(ProcNode::new($func_name)))
                    )
        }

        def_proc!(is_null, is_empty);
        def_proc!(is_boolean, is_bool);
        def_proc!(is_symbol, is_symbol);
        def_proc!(is_string, is_string);
        def_proc!(is_pair, is_pair);
        def_proc!(is_char, is_char);
        def_proc!(is_int, is_int);

        add_proc!("null?", is_null);
        add_proc!("boolean?", is_boolean);
        add_proc!("symbol?", is_symbol);
        add_proc!("string?", is_string);
        add_proc!("char?", is_char);
        add_proc!("integer?", is_int);
        add_proc!("+", add);
        add_proc!("-", sub);
        add_proc!("*", mul);
        add_proc!("/", div);
        add_proc!("eq?", eq);
        add_proc!("=", eq);
        add_proc!("<", less);
        add_proc!(">", large);
        add_proc!("pair?", is_pair);
        add_proc!("car", car);
        add_proc!("cdr", cdr);
        add_proc!("cons", cons);
    }
}

fn add(args: Expr) -> Expr {
    let mut res = 0is;
    let mut exps = args;
    loop {
        if exps.is_empty() { break; }
        res += exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn sub(args: Expr) -> Expr {
    let mut res = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        res -= exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn mul(args: Expr) -> Expr {
    let mut res = 1is;
    let mut exps = args;
    loop {
        if exps.is_empty() { break; }
        res *= exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn div(args: Expr) -> Expr {
    let mut exps = args;
    let mut res = exps.car().as_int();
    exps = exps.cdr();
    loop {
        if exps.is_empty() { break; }
        let nxt = exps.car().as_int();
        if nxt == 0 {
            return Expr::Symbol(SymbolNode::new("Fail"));
        }
        res /= nxt;
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn cons(args: Expr) -> Expr {
    let obj1 = args.car();
    let obj2 = args.c("da");
    Expr::Pair(PairNode::new(obj1, Expr::Pair(PairNode::new(obj2, Expr::Nil))))
}

fn eq(args: Expr) -> Expr {
    let obj1 = args.car();
    let obj2 = args.c("da");
    Expr::Bool(BoolNode::new(obj1 == obj2))
}

fn less(args: Expr) -> Expr {
    let val = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        if val >= exps.car().as_int() {
            return Expr::Bool(BoolNode::new(false));
        }
        exps = exps.cdr();
    }
    Expr::Bool(BoolNode::new(true))
}

fn car(args: Expr) -> Expr {
    assert!(args.car().is_pair());
    args.c("aa")
}

fn cdr(args: Expr) -> Expr {
    assert!(args.car().is_pair());
    args.c("ad")
}

fn large(args: Expr) -> Expr {
    let val = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        if val <= exps.car().as_int() {
            return Expr::Bool(BoolNode::new(false));
        }
        exps = exps.cdr();
    }
    Expr::Bool(BoolNode::new(true))
}

#[test]
fn test_env() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let val = env.str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");

    env.str_def("1", Expr::Int(IntNode::new(1)));
    let val = env.str_lookup("1");
    assert!(val.unwrap().as_int() == 1);

    env.str_def("1", Expr::Int(IntNode::new(2)));
    let val = env.str_lookup("1");
    assert!(val.unwrap().as_int() == 2);

    env.str_def("sym", Expr::Int(IntNode::new(2)));
    let val = env.str_lookup("sym");
    assert!(val.unwrap().as_int() == 2);

    let val = env.str_lookup("null?");
    assert!(val.unwrap().is_proc());
    let val = env.str_lookup("char?");
    assert!(val.unwrap().is_proc());
    let val = env.str_lookup("integer?");
    assert!(val.unwrap().is_proc());

    let val = env.str_lookup(">");
    assert!(val.unwrap().is_proc());

    let val = env.str_lookup("<");
    assert!(val.unwrap().is_proc());

}

#[test]
fn test_env_extend() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val")), Expr::Nil));

    let extend_env = env.extend(vars, vals);
    let val = extend_env.clone().borrow_mut().str_lookup("var");
    assert!(val.unwrap().as_str() == "val");

    let val = extend_env.clone().borrow_mut().str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var_x")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val_x")), Expr::Nil));

    let extend_env = extend_env.clone().borrow_mut().extend(vars, vals);
    let val = extend_env.clone().borrow_mut().str_lookup("var_x");
    assert!(val.unwrap().as_str() == "val_x");

    extend_env.clone().borrow_mut().str_def("1", Expr::Str(StrNode::new("1")));

    let val = extend_env.clone().borrow_mut().str_lookup("1");
    assert!(val.unwrap().as_str() == "1");
}

#[test]
fn test_env_parent() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val")), Expr::Nil));

    let extend_env = env.extend(vars, vals);
    let parent = extend_env.clone().borrow_mut().parent().unwrap();
    let val = parent.clone().borrow_mut().str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");
}

#[bench]
fn env_bench(b: &mut Bencher) {
    fn test_env() {
        let mut env = Env::new();
        for i in 1..1000 {
            let key = i.to_string();
            env.def_var(key.clone(), Expr::Str(StrNode::new("world")));
            let val = env.lookup(key);
            assert!(val.unwrap().as_str() == "world");
        }
    }

    b.iter(|| test_env());
}

#[bench]
fn env_bench_iter(b: &mut Bencher) {
    fn test_env() {
        let mut env = Env::new();
        for i in 1..1000 {
            env.str_def("hello", Expr::Str(StrNode::new("world")));
            let val = env.str_lookup("hello");
            assert!(val.unwrap().as_str() == "world");
        }
    }

    b.iter(|| test_env());
}
<|endoftext|>


<commit_before>
use graphics::*;
use piston::*;

use board::Board;
use number_renderer::NumberRenderer;
use settings::Settings;
use opengl_graphics::{
    Gl,
    Texture,
};

pub struct App<'a> {
    board: Board<'a>,
    number_renderer: Option<NumberRenderer>,
    settings: &'a Settings,

    logo: Option<Texture>,
    comment1: Option<Texture>,
    comment2: Option<Texture>,
    window_background_color: [f32, ..4],

    gl: Gl,
}

impl<'a> App<'a> {
    pub fn new(settings: &'a Settings) -> App<'a> {
        App {
            board: Board::new(settings),
            number_renderer: None,
            settings: settings,

            logo: None,
            comment1: None,
            comment2: None,
            window_background_color: [1.0, 1.0, 1.0, 1.0],

            gl: Gl::new(),
        }
    }
}

impl<'a> App<'a> {
    fn render_ui(&mut self, c: &Context) {
        // logo
        c.trans(self.settings.board_padding, self.settings.board_padding)
         .image(self.logo.get_ref())
         .rgb(self.settings.text_dark_color[0],
              self.settings.text_dark_color[1],
              self.settings.text_dark_color[2])
         .draw(&mut self.gl);

        c.view()
         .rect(self.settings.best_rect[0],
               self.settings.best_rect[1],
               self.settings.best_rect[2],
               self.settings.best_rect[3])
         .rgba(self.settings.label_color[0],
               self.settings.label_color[1],
               self.settings.label_color[2],
               1.0)
         .draw(&mut self.gl);

        let comment1_offset_y = self.settings.comment1_offset_y;
        let comment1 = self.comment1.as_ref().unwrap();
        App::render_comment(self.settings, comment1, comment1_offset_y, c, &mut self.gl);
        let comment2_offset_y = self.settings.comment2_offset_y;
        let comment2 = self.comment2.as_ref().unwrap();
        App::render_comment(self.settings, comment2, comment2_offset_y, c, &mut self.gl);
    }

    fn render_comment(settings: &Settings, comment: &Texture, y: f64, c: &Context, gl: &mut Gl) {
        let (width, height) = comment.get_size();
        let w = settings.window_size[0] as f64 - 2.0 * settings.board_padding;
        let h = height as f64 * w / width as f64;
        c.rect(settings.board_padding, y, w, h)
         .image(comment)
         .rgb(settings.text_dark_color[0],
              settings.text_dark_color[1],
              settings.text_dark_color[2])
         .draw(gl);
    }
}

impl<'a> Game for App<'a> {
    fn load(&mut self) {
        let asset_store = AssetStore::from_folder(self.settings.asset_folder.as_slice());
        self.number_renderer = Some(NumberRenderer::new(&asset_store));

        self.logo = Some(Texture::from_path(&asset_store.path("logo.png").unwrap()).unwrap());
        self.comment1 = Some(Texture::from_path(&asset_store.path("comment1.png").unwrap()).unwrap());
        self.comment2 = Some(Texture::from_path(&asset_store.path("comment2.png").unwrap()).unwrap());
    }

    fn render(&mut self, args: &RenderArgs) {
        self.gl.viewport(0, 0, args.width as i32, args.height as i32);
        let ref c = Context::abs(args.width as f64, args.height as f64);
        c.color(self.window_background_color).draw(&mut self.gl);

        self.render_ui(c);
        self.board.render(self.number_renderer.get_ref(), c, &mut self.gl);
    }

    fn update(&mut self, args: &UpdateArgs) {
        self.board.update(args.dt);
    }

    fn key_press(&mut self, args: &KeyPressArgs) {
        if args.key == keyboard::Left {
            self.board.merge_from_right_to_left();
        }
        if args.key == keyboard::Right {
            self.board.merge_from_left_to_right();
        }
        if args.key == keyboard::Up {
            self.board.merge_from_bottom_to_top();
        }
        if args.key == keyboard::Down {
            self.board.merge_from_top_to_bottom();
        }
        if args.key == keyboard::Space {
            self.board = Board::new(self.settings);
        }
    }
}

<commit_msg>update for new piston changes<commit_after>
use graphics::*;
use piston::*;

use board::Board;
use number_renderer::NumberRenderer;
use settings::Settings;
use sdl2_game_window::GameWindowSDL2;
use opengl_graphics::{
    Gl,
    Texture,
};

pub struct App<'a> {
    board: Board<'a>,
    number_renderer: Option<NumberRenderer>,
    settings: &'a Settings,

    logo: Option<Texture>,
    comment1: Option<Texture>,
    comment2: Option<Texture>,
    window_background_color: [f32, ..4],

    gl: Gl,
}

impl<'a> App<'a> {
    pub fn new(settings: &'a Settings) -> App<'a> {
        App {
            board: Board::new(settings),
            number_renderer: None,
            settings: settings,

            logo: None,
            comment1: None,
            comment2: None,
            window_background_color: [1.0, 1.0, 1.0, 1.0],

            gl: Gl::new(),
        }
    }

    fn render_ui(&mut self, c: &Context) {
        // logo
        c.trans(self.settings.board_padding, self.settings.board_padding)
         .image(self.logo.get_ref())
         .rgb(self.settings.text_dark_color[0],
              self.settings.text_dark_color[1],
              self.settings.text_dark_color[2])
         .draw(&mut self.gl);

        c.view()
         .rect(self.settings.best_rect[0],
               self.settings.best_rect[1],
               self.settings.best_rect[2],
               self.settings.best_rect[3])
         .rgba(self.settings.label_color[0],
               self.settings.label_color[1],
               self.settings.label_color[2],
               1.0)
         .draw(&mut self.gl);

        let comment1_offset_y = self.settings.comment1_offset_y;
        let comment1 = self.comment1.as_ref().unwrap();
        App::render_comment(self.settings, comment1, comment1_offset_y, c, &mut self.gl);
        let comment2_offset_y = self.settings.comment2_offset_y;
        let comment2 = self.comment2.as_ref().unwrap();
        App::render_comment(self.settings, comment2, comment2_offset_y, c, &mut self.gl);
    }

    fn render_comment(settings: &Settings, comment: &Texture, y: f64, c: &Context, gl: &mut Gl) {
        let (width, height) = comment.get_size();
        let w = settings.window_size[0] as f64 - 2.0 * settings.board_padding;
        let h = height as f64 * w / width as f64;
        c.rect(settings.board_padding, y, w, h)
         .image(comment)
         .rgb(settings.text_dark_color[0],
              settings.text_dark_color[1],
              settings.text_dark_color[2])
         .draw(gl);
    }
}

impl<'a> Game<GameWindowSDL2> for App<'a> {
    fn load(&mut self, _window: &mut GameWindowSDL2) {
        let asset_store = AssetStore::from_folder(self.settings.asset_folder.as_slice());
        self.number_renderer = Some(NumberRenderer::new(&asset_store));

        self.logo = Some(Texture::from_path(&asset_store.path("logo.png").unwrap()).unwrap());
        self.comment1 = Some(Texture::from_path(&asset_store.path("comment1.png").unwrap()).unwrap());
        self.comment2 = Some(Texture::from_path(&asset_store.path("comment2.png").unwrap()).unwrap());
    }

    fn render(&mut self, _window: &mut GameWindowSDL2, args: &RenderArgs) {
        self.gl.viewport(0, 0, args.width as i32, args.height as i32);
        let ref c = Context::abs(args.width as f64, args.height as f64);
        c.color(self.window_background_color).draw(&mut self.gl);

        self.render_ui(c);
        self.board.render(self.number_renderer.get_ref(), c, &mut self.gl);
    }

    fn update(&mut self, _window: &mut GameWindowSDL2, args: &UpdateArgs) {
        self.board.update(args.dt);
    }

    fn key_press(&mut self, _window: &mut GameWindowSDL2, args: &KeyPressArgs) {
        if args.key == keyboard::Left {
            self.board.merge_from_right_to_left();
        }
        if args.key == keyboard::Right {
            self.board.merge_from_left_to_right();
        }
        if args.key == keyboard::Up {
            self.board.merge_from_bottom_to_top();
        }
        if args.key == keyboard::Down {
            self.board.merge_from_top_to_bottom();
        }
        if args.key == keyboard::Space {
            self.board = Board::new(self.settings);
        }
    }
}

<|endoftext|>


<commit_before>#![allow(unsafe_code)]
/// We use this because we never use the weak count on the std
/// `Arc`, but we use a LOT of `Arc`'s, so the extra 8 bytes
/// turn into a huge overhead.
use std::{
    alloc::{alloc, dealloc, Layout},
    convert::TryFrom,
    fmt::{self, Debug},
    mem,
    ops::Deref,
    ptr,
    sync::atomic::{AtomicUsize, Ordering},
};

// we make this repr(C) because we do a raw
// write to the beginning where we expect
// the rc to be.
#[repr(C)]
struct ArcInner<T: ?Sized> {
    rc: AtomicUsize,
    inner: T,
}

pub struct Arc<T: ?Sized> {
    ptr: *mut ArcInner<T>,
}

unsafe impl<T: Send + Sync + ?Sized> Send for Arc<T> {}
unsafe impl<T: Send + Sync + ?Sized> Sync for Arc<T> {}

impl<T: Debug> Debug for Arc<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        f.debug_map().entry(&"inner", unsafe { &(*self.ptr).inner }).finish()
    }
}

impl<T> Arc<T> {
    pub fn new(inner: T) -> Arc<T> {
        let bx = Box::new(ArcInner { inner, rc: AtomicUsize::new(1) });
        let ptr = Box::into_raw(bx);
        Arc { ptr }
    }

    pub fn copy_from_slice(s: &[T]) -> Arc<[T]> {
        let align =
            std::cmp::max(mem::align_of::<T>(), mem::align_of::<AtomicUsize>());

        let rc_width = std::cmp::max(align, mem::size_of::<AtomicUsize>());
        let data_width = mem::size_of::<T>().checked_mul(s.len()).unwrap();

        let size = rc_width.checked_add(data_width).unwrap();

        let layout = Layout::from_size_align(size, align).unwrap();

        unsafe {
            let ptr = alloc(layout);

            assert!(!ptr.is_null(), "failed to allocate Arc");
            #[allow(clippy::cast_ptr_alignment)]
            ptr::write(ptr as _, AtomicUsize::new(1));

            let data_ptr = ptr.add(rc_width);
            ptr::copy_nonoverlapping(s.as_ptr(), data_ptr as _, s.len());

            let fat_ptr: *const ArcInner<[T]> = Arc::fatten(ptr, s.len());

            Arc { ptr: fat_ptr as *mut _ }
        }
    }

    /// <https://users.rust-lang.org/t/construct-fat-pointer-to-struct/29198/9>
    #[allow(trivial_casts)]
    fn fatten(data: *const u8, len: usize) -> *const ArcInner<[T]> {
        // Requirements of slice::from_raw_parts.
        assert!(!data.is_null());
        assert!(isize::try_from(len).is_ok());

        let slice =
            unsafe { core::slice::from_raw_parts(data as *const (), len) };
        slice as *const [()] as *const _
    }

    pub fn into_raw(arc: Arc<T>) -> *const T {
        let ptr = unsafe { &(*arc.ptr).inner };
        #[allow(clippy::mem_forget)]
        mem::forget(arc);
        ptr
    }

    pub unsafe fn from_raw(ptr: *const T) -> Arc<T> {
        let align =
            std::cmp::max(mem::align_of::<T>(), mem::align_of::<AtomicUsize>());

        let rc_width = std::cmp::max(align, mem::size_of::<AtomicUsize>());

        let sub_ptr = (ptr as *const u8).sub(rc_width) as *mut ArcInner<T>;

        Arc { ptr: sub_ptr }
    }
}

impl<T: ?Sized> Arc<T> {
    pub fn strong_count(arc: &Arc<T>) -> usize {
        unsafe { (*arc.ptr).rc.load(Ordering::Acquire) }
    }

    pub fn get_mut(arc: &mut Arc<T>) -> Option<&mut T> {
        if Arc::strong_count(arc) == 1 {
            Some(unsafe { &mut arc.ptr.as_mut().unwrap().inner })
        } else {
            None
        }
    }
}

impl<T: ?Sized + Clone> Arc<T> {
    pub fn make_mut(arc: &mut Arc<T>) -> &mut T {
        if Arc::strong_count(arc) != 1 {
            *arc = Arc::new((**arc).clone());
            assert_eq!(Arc::strong_count(arc), 1);
        }
        Arc::get_mut(arc).unwrap()
    }
}

impl<T: Default> Default for Arc<T> {
    fn default() -> Arc<T> {
        Arc::new(T::default())
    }
}

impl<T: ?Sized> Clone for Arc<T> {
    fn clone(&self) -> Arc<T> {
        unsafe {
            (*self.ptr).rc.fetch_add(1, Ordering::Release);
        }
        Arc { ptr: self.ptr }
    }
}

impl<T: ?Sized> Drop for Arc<T> {
    fn drop(&mut self) {
        unsafe {
            let rc = (*self.ptr).rc.fetch_sub(1, Ordering::Release) - 1;
            if rc == 0 {
                Box::from_raw(self.ptr);
            }
        }
    }
}

impl<T: Copy> From<&[T]> for Arc<[T]> {
    #[inline]
    fn from(s: &[T]) -> Arc<[T]> {
        Arc::copy_from_slice(s)
    }
}

#[allow(clippy::fallible_impl_from)]
impl<T> From<Box<T>> for Arc<T> {
    #[inline]
    fn from(b: Box<T>) -> Arc<T> {
        let align =
            std::cmp::max(mem::align_of::<T>(), mem::align_of::<AtomicUsize>());

        let rc_width = std::cmp::max(align, mem::size_of::<AtomicUsize>());

        let size = rc_width.checked_add(mem::size_of::<T>()).unwrap();

        unsafe {
            let dst_layout = Layout::from_size_align(size, align).unwrap();
            let dst = alloc(dst_layout);
            assert!(!dst.is_null(), "failed to allocate Arc");

            let data_ptr = dst.add(rc_width);
            #[allow(clippy::cast_ptr_alignment)]
            ptr::write(dst as _, AtomicUsize::new(1));
            let src = Box::into_raw(b);
            ptr::copy(src, data_ptr as *mut T, 1);

            // free the old box memory without running Drop
            let src_layout = Layout::new::<T>();
            dealloc(src as *mut u8, src_layout);

            Arc { ptr: dst as *mut _ }
        }
    }
}

impl<T> From<Vec<T>> for Arc<[T]> {
    #[inline]
    fn from(mut v: Vec<T>) -> Arc<[T]> {
        unsafe {
            let arc = Arc::copy_from_slice(&v);

            // Allow the Vec to free its memory, but not destroy its contents
            v.set_len(0);

            arc
        }
    }
}

impl<T: ?Sized> Deref for Arc<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &(*self.ptr).inner }
    }
}

impl<T: ?Sized> std::borrow::Borrow<T> for Arc<T> {
    fn borrow(&self) -> &T {
        &**self
    }
}

impl<T: ?Sized> AsRef<T> for Arc<T> {
    fn as_ref(&self) -> &T {
        &**self
    }
}
<commit_msg>Use Relaxed ref incr. Add Acquire fence before dropping data. Simplify layout generation<commit_after>#![allow(unsafe_code)]
/// We use this because we never use the weak count on the std
/// `Arc`, but we use a LOT of `Arc`'s, so the extra 8 bytes
/// turn into a huge overhead.
use std::{
    alloc::{alloc, dealloc, Layout},
    convert::TryFrom,
    fmt::{self, Debug},
    mem,
    ops::Deref,
    ptr,
    sync::atomic::{AtomicUsize, Ordering},
};

// we make this repr(C) because we do a raw
// write to the beginning where we expect
// the rc to be.
#[repr(C)]
struct ArcInner<T: ?Sized> {
    rc: AtomicUsize,
    inner: T,
}

pub struct Arc<T: ?Sized> {
    ptr: *mut ArcInner<T>,
}

unsafe impl<T: Send + Sync + ?Sized> Send for Arc<T> {}
unsafe impl<T: Send + Sync + ?Sized> Sync for Arc<T> {}

impl<T: Debug> Debug for Arc<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        f.debug_map().entry(&"inner", unsafe { &(*self.ptr).inner }).finish()
    }
}

impl<T> Arc<T> {
    pub fn new(inner: T) -> Arc<T> {
        let bx = Box::new(ArcInner { inner, rc: AtomicUsize::new(1) });
        let ptr = Box::into_raw(bx);
        Arc { ptr }
    }

    pub fn copy_from_slice(s: &[T]) -> Arc<[T]> {
        let align =
            std::cmp::max(mem::align_of::<T>(), mem::align_of::<AtomicUsize>());

        let rc_width = std::cmp::max(align, mem::size_of::<AtomicUsize>());
        let data_width = mem::size_of::<T>().checked_mul(s.len()).unwrap();

        let size = rc_width.checked_add(data_width).unwrap();

        let layout = Layout::from_size_align(size, align).unwrap();

        unsafe {
            let ptr = alloc(layout);

            assert!(!ptr.is_null(), "failed to allocate Arc");
            #[allow(clippy::cast_ptr_alignment)]
            ptr::write(ptr as _, AtomicUsize::new(1));

            let data_ptr = ptr.add(rc_width);
            ptr::copy_nonoverlapping(s.as_ptr(), data_ptr as _, s.len());

            let fat_ptr: *const ArcInner<[T]> = Arc::fatten(ptr, s.len());

            Arc { ptr: fat_ptr as *mut _ }
        }
    }

    /// <https://users.rust-lang.org/t/construct-fat-pointer-to-struct/29198/9>
    #[allow(trivial_casts)]
    fn fatten(data: *const u8, len: usize) -> *const ArcInner<[T]> {
        // Requirements of slice::from_raw_parts.
        assert!(!data.is_null());
        assert!(isize::try_from(len).is_ok());

        let slice =
            unsafe { core::slice::from_raw_parts(data as *const (), len) };
        slice as *const [()] as *const _
    }

    pub fn into_raw(arc: Arc<T>) -> *const T {
        let ptr = unsafe { &(*arc.ptr).inner };
        #[allow(clippy::mem_forget)]
        mem::forget(arc);
        ptr
    }

    pub unsafe fn from_raw(ptr: *const T) -> Arc<T> {
        let align =
            std::cmp::max(mem::align_of::<T>(), mem::align_of::<AtomicUsize>());

        let rc_width = std::cmp::max(align, mem::size_of::<AtomicUsize>());

        let sub_ptr = (ptr as *const u8).sub(rc_width) as *mut ArcInner<T>;

        Arc { ptr: sub_ptr }
    }
}

impl<T: ?Sized> Arc<T> {
    pub fn strong_count(arc: &Arc<T>) -> usize {
        unsafe { (*arc.ptr).rc.load(Ordering::Acquire) }
    }

    pub fn get_mut(arc: &mut Arc<T>) -> Option<&mut T> {
        if Arc::strong_count(arc) == 1 {
            Some(unsafe { &mut arc.ptr.as_mut().unwrap().inner })
        } else {
            None
        }
    }
}

impl<T: ?Sized + Clone> Arc<T> {
    pub fn make_mut(arc: &mut Arc<T>) -> &mut T {
        if Arc::strong_count(arc) != 1 {
            *arc = Arc::new((**arc).clone());
            assert_eq!(Arc::strong_count(arc), 1);
        }
        Arc::get_mut(arc).unwrap()
    }
}

impl<T: Default> Default for Arc<T> {
    fn default() -> Arc<T> {
        Arc::new(T::default())
    }
}

impl<T: ?Sized> Clone for Arc<T> {
    fn clone(&self) -> Arc<T> {
        // safe to use Relaxed ordering below because
        // of the required synchronization for passing
        // any objects to another thread.
        let last_count =
            unsafe { (*self.ptr).rc.fetch_add(1, Ordering::Relaxed) };

        if last_count == usize::max_value() {
            #[cold]
            std::process::abort();
        }

        Arc { ptr: self.ptr }
    }
}

impl<T: ?Sized> Drop for Arc<T> {
    fn drop(&mut self) {
        unsafe {
            let rc = (*self.ptr).rc.fetch_sub(1, Ordering::Release) - 1;
            if rc == 0 {
                std::sync::atomic::fence(Ordering::Acquire);
                Box::from_raw(self.ptr);
            }
        }
    }
}

impl<T: Copy> From<&[T]> for Arc<[T]> {
    #[inline]
    fn from(s: &[T]) -> Arc<[T]> {
        Arc::copy_from_slice(s)
    }
}

#[allow(clippy::fallible_impl_from)]
impl<T> From<Box<T>> for Arc<T> {
    #[inline]
    fn from(b: Box<T>) -> Arc<T> {
        let align =
            std::cmp::max(mem::align_of::<T>(), mem::align_of::<AtomicUsize>());

        let rc_width = std::cmp::max(align, mem::size_of::<AtomicUsize>());

        unsafe {
            let dst_layout = Layout::new::<ArcInner<T>>();
            let dst = alloc(dst_layout);
            assert!(!dst.is_null(), "failed to allocate Arc");

            let data_ptr = dst.add(rc_width);
            #[allow(clippy::cast_ptr_alignment)]
            ptr::write(dst as _, AtomicUsize::new(1));
            let src = Box::into_raw(b);
            ptr::copy(src, data_ptr as *mut T, 1);

            // free the old box memory without running Drop
            let src_layout = Layout::new::<T>();
            dealloc(src as *mut u8, src_layout);

            Arc { ptr: dst as *mut _ }
        }
    }
}

impl<T> From<Vec<T>> for Arc<[T]> {
    #[inline]
    fn from(mut v: Vec<T>) -> Arc<[T]> {
        unsafe {
            let arc = Arc::copy_from_slice(&v);

            // Allow the Vec to free its memory, but not destroy its contents
            v.set_len(0);

            arc
        }
    }
}

impl<T: ?Sized> Deref for Arc<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &(*self.ptr).inner }
    }
}

impl<T: ?Sized> std::borrow::Borrow<T> for Arc<T> {
    fn borrow(&self) -> &T {
        &**self
    }
}

impl<T: ?Sized> AsRef<T> for Arc<T> {
    fn as_ref(&self) -> &T {
        &**self
    }
}
<|endoftext|>


<commit_before>
pub trait MBC {
	fn readrom(&self, a: u16) -> u8;
	fn readram(&self, a: u16) -> u8;
	fn writerom(&mut self, a: u16, v: u8);
	fn writeram(&mut self, a: u16, v: u8);
}

struct MBC0 {
	priv rom: ~[u8],
}

struct MBC1 {
	priv rom: ~[u8],
	priv ram: ~[u8],
	priv ram_on: bool,
	priv ram_mode: bool,
	priv rombank: u32,
	priv rambank: u32,
}

pub fn get_mbc(data: ~[u8]) -> ~MBC {
	if data.len() < 0x149 { fail!("Rom size to small"); }
	let ramsize = match data[0x149] {
		1 => 0x800,
		2 => 0x2000,
		3 => 0x8000,
		_ => 0,
	};
	match data[0x147] {
		0x00 => (~MBC0 { rom: data }) as ~MBC,
		0x01 .. 0x03 => (~MBC1 {
			rom: data,
			ram: ::std::vec::from_elem(ramsize, 0u8),
			ram_on: false,
			ram_mode: false,
			rombank: 1,
			rambank: 0,
		}) as ~MBC,
		m => fail!("Unsupported MBC type: {:02X}", m),
	}
}

impl MBC for MBC0 {
	fn readrom(&self, a: u16) -> u8 { self.rom[a] }
	fn readram(&self, _a: u16) -> u8 { 0 }
	fn writerom(&mut self, _a: u16, _v: u8) { () }
	fn writeram(&mut self, _a: u16, _v: u8) { () }
}

impl MBC for MBC1 {
	fn readrom(&self, a: u16) -> u8 {
		if a < 0x4000 { self.rom[a] }
		else { self.rom[self.rombank * 0x4000 | ((a as u32) & 0x3FFF) ] }
	}
	fn readram(&self, a: u16) -> u8 {
		if !self.ram_on || !self.ram_mode { 0 }
		else { self.ram[self.rambank * 0x2000 | a as u32] }
	}

	fn writerom(&mut self, a: u16, v: u8) {
		match a {
			0x0000 .. 0x1FFF => { self.ram_on = (v == 0x0A); },
			0x2000 .. 0x3FFF => {
				self.rombank = (self.rombank & 0x60) | match (v as u32) & 0x1F { 0 => 1, n => n }
			},
			0x4000 .. 0x5FFF => {
				if !self.ram_mode {
					self.rombank = self.rombank & 0x1F | (((v as u32) & 0x03) << 5)
				} else {
					self.rambank = (v as u32) & 0x03;
				}
			},
			0x6000 .. 0x7FFF => { self.ram_mode = (v & 0x01) == 0x01; },
			_ => fail!("Could not write to {:04X} (MBC1)", a),
		}
	}

	fn writeram(&mut self, a: u16, v: u8) {
		if !self.ram_on || !self.ram_mode { return }
		self.ram[self.rambank * 0x2000 | a as u32] = v;
	}
}

<commit_msg>Added MBC3<commit_after>
pub trait MBC {
	fn readrom(&self, a: u16) -> u8;
	fn readram(&self, a: u16) -> u8;
	fn writerom(&mut self, a: u16, v: u8);
	fn writeram(&mut self, a: u16, v: u8);
}

struct MBC0 {
	priv rom: ~[u8],
}

impl MBC0 {
	pub fn new(data: ~[u8]) -> MBC0 {
		MBC0 { rom: data }
	}
}

struct MBC1 {
	priv rom: ~[u8],
	priv ram: ~[u8],
	priv ram_on: bool,
	priv ram_mode: bool,
	priv rombank: u32,
	priv rambank: u32,
}

impl MBC1 {
	pub fn new(data: ~[u8]) -> MBC1 {
		let ramsize = ram_size(data[0x149]);
		MBC1 {
			rom: data,
			ram: ::std::vec::from_elem(ramsize, 0u8),
			ram_on: false,
			ram_mode: false,
			rombank: 1,
			rambank: 0,
		}
	}
}

struct MBC3 {
	priv rom: ~[u8],
	priv ram: ~[u8],
	priv rombank: u32,
	priv rambank: u32,
	priv ram_on: bool,
}

impl MBC3 {
	pub fn new(data: ~[u8]) -> MBC3 {
		let ramsize = ram_size(data[0x149]);
		MBC3 {
			rom: data,
			ram: ::std::vec::from_elem(ramsize, 0u8),
			rombank: 1,
			rambank: 0,
			ram_on: false,
		}
	}
}

pub fn get_mbc(data: ~[u8]) -> ~MBC {
	if data.len() < 0x149 { fail!("Rom size to small"); }
	match data[0x147] {
		0x00 => ~MBC0::new(data) as ~MBC,
		0x01 .. 0x03 => ~MBC1::new(data) as ~MBC,
		0x0F .. 0x13 => ~MBC3::new(data) as ~MBC,
		m => fail!("Unsupported MBC type: {:02X}", m),
	}
}

fn ram_size(v: u8) -> uint {
	match v {
		1 => 0x800,
		2 => 0x2000,
		3 => 0x8000,
		_ => 0,
	}
}

impl MBC for MBC0 {
	fn readrom(&self, a: u16) -> u8 { self.rom[a] }
	fn readram(&self, _a: u16) -> u8 { 0 }
	fn writerom(&mut self, _a: u16, _v: u8) { () }
	fn writeram(&mut self, _a: u16, _v: u8) { () }
}

impl MBC for MBC1 {
	fn readrom(&self, a: u16) -> u8 {
		if a < 0x4000 { self.rom[a] }
		else { self.rom[self.rombank * 0x4000 | ((a as u32) & 0x3FFF) ] }
	}
	fn readram(&self, a: u16) -> u8 {
		if !self.ram_on { return 0 }
		let rambank = if self.ram_mode { self.rambank } else { 0 };
		self.ram[rambank * 0x2000 | a as u32]
	}

	fn writerom(&mut self, a: u16, v: u8) {
		match a {
			0x0000 .. 0x1FFF => { self.ram_on = (v == 0x0A); },
			0x2000 .. 0x3FFF => {
				self.rombank = (self.rombank & 0x60) | match (v as u32) & 0x1F { 0 => 1, n => n }
			},
			0x4000 .. 0x5FFF => {
				if !self.ram_mode {
					self.rombank = self.rombank & 0x1F | (((v as u32) & 0x03) << 5)
				} else {
					self.rambank = (v as u32) & 0x03;
				}
			},
			0x6000 .. 0x7FFF => { self.ram_mode = (v & 0x01) == 0x01; },
			_ => fail!("Could not write to {:04X} (MBC1)", a),
		}
	}

	fn writeram(&mut self, a: u16, v: u8) {
		if !self.ram_on { return }
		let rambank = if self.ram_mode { self.rambank } else { 0 };
		self.ram[rambank * 0x2000 | a as u32] = v;
	}
}

impl MBC for MBC3 {
	fn readrom(&self, a: u16) -> u8 {
		if a < 0x4000 { self.rom[a] }
		else { self.rom[self.rombank * 0x4000 | ((a as u32) & 0x3FFF)] }
	}
	fn readram(&self, a: u16) -> u8 {
		if !self.ram_on { return 0 }
		if self.rambank <= 3 {
			self.ram[self.rambank * 0x2000 | ((a as u32) & 0x1FFF)]
		} else {
			0 // TODO: RTC
		}
	}
	fn writerom(&mut self, a: u16, v: u8) {
		match a {
			0x0000 .. 0x1FFF => self.ram_on = (v == 0x0A),
			0x2000 .. 0x3FFF => {
				self.rombank = match v & 0x7F { 0 => 1, n => n as u32 }
			},
			0x4000 .. 0x5FFF => self.rambank = v as u32,
			0x6000 .. 0x7FFF => {}, // TODO: RTC
			_ => fail!("Could not write to {:04X} (MBC3)", a),
		}
	}
	fn writeram(&mut self, a: u16, v: u8) {
		if self.ram_on == false { return }
		if self.rambank <= 3 {
			self.ram[self.rambank * 0x2000 | ((a as u32) & 0x1FFF)] = v;
		} else {
			// TODO: RTC
		}
	}
}

<|endoftext|>


<commit_before>// TODO: Clean code, please
// TODO: Check types used. Try to minimize the memory used
// TODO: Add more tests.
// TODO: Handle empty imput
// TODO: Better UI. Colors? Num of matches?
// TODO: Try to do the fuzzy search async?
extern crate scout;
extern crate docopt;
extern crate termios;
extern crate termion;

use std::env;

use termios::{Termios, TCSANOW, ECHO, ICANON, tcsetattr};
use termion::event::Key;
use termion::input::TermRead;
use termion::screen::*;
use std::io::{self, Read, Write};
use std::os::unix::io::AsRawFd;

const USAGE: &'static str = "
Scout: Small fuzzy finder

This program expects a list of items in the
standard input, so it is better to use it
with pipes.

Usage:
  scout [options]

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

Example:
  $ ls | scout
";

fn magic() -> Result<String, io::Error> {
    // Collect initial input
    let mut buffer = String::new();
    try!(io::stdin().read_to_string(&mut buffer));
    let input: Vec<&str> = buffer.split("\n").collect();

    // I need to transform tty into raw mode to get chars byte by byte.
    // Check termios crate
    // see: http://stackoverflow.com/a/37416107
    let tty = termion::get_tty().unwrap();
    let fd = tty.as_raw_fd();
    let original_tty = Termios::from_fd(fd).unwrap();
    let mut new_tty = original_tty.clone();  // make a mutable copy of termios
                                            // that we will modify
    new_tty.c_lflag &= !(ICANON | ECHO); // no echo and canonical mode
    tcsetattr(fd, TCSANOW, &mut new_tty).unwrap();

    // Then we can use this tty to create our screen with the help
    // of termion crate
    let mut screen = AlternateScreen::from(tty);
    let mut result = String::new();
    let mut query: Vec<char> = vec![];
    let mut buffer: Vec<u8> = Vec::with_capacity(2);

    'event: loop {
        let s: String = query.iter().cloned().collect();
        let query_chars: Vec<char> = query.iter().cloned().collect();
        let suggestions = scout::explore(&input, &query_chars);

        write!(
            &mut screen,
            "{}{}> {}\n",
            termion::clear::All,
            termion::cursor::Goto(1, 1),
            s,
        ).unwrap();

        for item in suggestions.iter().take(21).cloned() {
            writeln!(&mut screen, "{}", item).unwrap();
        }

        write!(
            &mut screen,
            "{}",
            termion::cursor::Goto((s.len() + 3) as u16, 1),
        ).unwrap();

        screen.flush().unwrap();

        // Some chars are 2 bytes at a time, so better
        // to read 2 by 2. E.g: Arrow keys
        let mut int_buffer = [0;2];
        buffer.clear();
        // Ensure that we read 2 bytes in an intermediate buffer
        //
        // If the amount of real bytes read is less than 2,
        // put only that byte in the buffer so we don't carry
        // junk.
        //
        // If the amount is 2, put both in the buffer
        match screen.read(&mut int_buffer) {
            Ok(1) => {
                buffer.push(int_buffer[0])
            },
            Ok(2) => {
                buffer = int_buffer.iter().map(|&x| x).collect()
            }
            Ok(_) => {},
            Err(_) => {}
        };

        // Now this buffer has the exact amount of bytes from
        // the input so we can use the #keys() function from termion
        // to read and transform those bytes into proper keys
        for c in buffer.keys() {
            match c.unwrap() {
                Key::Esc => break 'event,
                Key::Backspace => {
                    let _ = query.pop();
                },
                Key::Char('\n') => {
                    // result = query.iter().cloned().collect();
                    if let Some(&choice) = suggestions.first() {
                        result = String::from(choice);
                    }
                    break 'event
                },
                Key::Char(c) => {
                    query.push(c as char);
                },
                _ => {
                    query.push('?');
                },
            }
        }
    };

    tcsetattr(fd, TCSANOW, & original_tty).unwrap();  // reset the stdin to

    Ok(result)
}

pub fn main() {
    docopt::Docopt::new(USAGE)
        .and_then(|doc| {
            doc.argv(env::args())
                .version(Some(scout::version()))
                .parse()
        })
        .unwrap_or_else(|e| e.exit());;

    match magic() {
        Ok(result) => println!("{}", result),
        Err(e) => println!("{:?}", e),
    }
}
<commit_msg>Add number of suggestions to prompt.<commit_after>// TODO: Clean code, please
// TODO: Check types used. Try to minimize the memory used
// TODO: Add more tests.
// TODO: Better UI. Colors? Num of matches?
// TODO: Try to do the fuzzy search async?
extern crate scout;
extern crate docopt;
extern crate termios;
extern crate termion;

use std::env;

use termios::{Termios, TCSANOW, ECHO, ICANON, tcsetattr};
use termion::event::Key;
use termion::input::TermRead;
use termion::screen::*;
use std::io::{self, Read, Write};
use std::os::unix::io::AsRawFd;

const USAGE: &'static str = "
Scout: Small fuzzy finder

This program expects a list of items in the
standard input, so it is better to use it
with pipes.

Usage:
  scout [options]

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

Example:
  $ ls | scout
";

fn magic() -> Result<String, io::Error> {
    // Collect initial input
    let mut buffer = String::new();
    try!(io::stdin().read_to_string(&mut buffer));
    let input: Vec<&str> = buffer.split("\n")
        .filter(|s| !s.is_empty())
        .collect();
    let width = format!("{}", input.len()).len();

    // I need to transform tty into raw mode to get chars byte by byte.
    // Check termios crate
    // see: http://stackoverflow.com/a/37416107
    let tty = termion::get_tty().unwrap();
    let fd = tty.as_raw_fd();
    let original_tty = Termios::from_fd(fd).unwrap();
    let mut new_tty = original_tty.clone();  // make a mutable copy of termios
                                            // that we will modify
    new_tty.c_lflag &= !(ICANON | ECHO); // no echo and canonical mode
    tcsetattr(fd, TCSANOW, &mut new_tty).unwrap();

    // Then we can use this tty to create our screen with the help
    // of termion crate
    let mut screen = AlternateScreen::from(tty);
    let mut result = String::new();
    let mut query: Vec<char> = vec![];
    let mut buffer: Vec<u8> = Vec::with_capacity(2);

    'event: loop {
        let s: String = query.iter().cloned().collect();
        let query_chars: Vec<char> = query.iter().cloned().collect();
        let suggestions = scout::explore(&input, &query_chars);

        // Clear the screen and put the cursor at the beginning
        writeln!(
            &mut screen,
            "{}{}",
            termion::clear::All,
            termion::cursor::Goto(1, 1),
        ).unwrap();

        // Print all the suggestions
        for item in suggestions.iter().take(21).cloned() {
            writeln!(&mut screen, "{}", item).unwrap();
        }

        // Go to the beginning again and redraw the prompt.
        // This will put the cursor at the end of it
        let prompt = format!("{:width$} > {}", suggestions.len(), s, width = width);
        write!(&mut screen, "{}{}", termion::cursor::Goto(1, 1), prompt).unwrap();

        screen.flush().unwrap();

        // Some chars are 2 bytes at a time, so better
        // to read 2 by 2. E.g: Arrow keys
        let mut int_buffer = [0;2];
        buffer.clear();
        // Ensure that we read 2 bytes in an intermediate buffer
        //
        // If the amount of real bytes read is less than 2,
        // put only that byte in the buffer so we don't carry
        // junk.
        //
        // If the amount is 2, put both in the buffer
        match screen.read(&mut int_buffer) {
            Ok(1) => {
                buffer.push(int_buffer[0])
            },
            Ok(2) => {
                buffer = int_buffer.iter().map(|&x| x).collect()
            }
            Ok(_) => {},
            Err(_) => {}
        };

        // Now this buffer has the exact amount of bytes from
        // the input so we can use the #keys() function from termion
        // to read and transform those bytes into proper keys
        for c in buffer.keys() {
            match c.unwrap() {
                Key::Esc => break 'event,
                Key::Backspace => {
                    let _ = query.pop();
                },
                Key::Char('\n') => {
                    // result = query.iter().cloned().collect();
                    if let Some(&choice) = suggestions.first() {
                        result = String::from(choice);
                    }
                    break 'event
                },
                Key::Char(c) => {
                    query.push(c as char);
                },
                _ => {},
            }
        }
    };

    tcsetattr(fd, TCSANOW, & original_tty).unwrap();  // reset the stdin to

    Ok(result)
}

pub fn main() {
    docopt::Docopt::new(USAGE)
        .and_then(|doc| {
            doc.argv(env::args())
                .version(Some(scout::version()))
                .parse()
        })
        .unwrap_or_else(|e| e.exit());;

    match magic() {
        Ok(result) => println!("{}", result),
        Err(e) => println!("{:?}", e),
    }
}
<|endoftext|>


<commit_before>use crate::*;
use helpers::check_arg_count;
use rustc_middle::ty::{self, TypeAndMut};
use rustc_ast::ast::Mutability;
use rustc_span::BytePos;
use rustc_target::abi::Size;
use std::convert::TryInto as _;
use crate::rustc_target::abi::LayoutOf as _;

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {

    fn handle_miri_get_backtrace(
        &mut self,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();
        let tcx = this.tcx;
        let &[flags] = check_arg_count(args)?;

        let flags = this.read_scalar(flags)?.to_u64()?;
        if flags != 0 {
            throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags);
        }

        let mut data = Vec::new();
        for frame in this.active_thread_stack().iter().rev() {
            let mut span = frame.current_span();
            // Match the behavior of runtime backtrace spans
            // by using a non-macro span in our backtrace. See `FunctionCx::debug_loc`.
            if span.from_expansion() && !tcx.sess.opts.debugging_opts.debug_macros {
                span = rustc_span::hygiene::walk_chain(span, frame.body.span.ctxt())
            }
            data.push((frame.instance, span.lo()));
        }

        let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| {
            // We represent a frame pointer by using the `span.lo` value
            // as an offset into the function's allocation. This gives us an
            // opaque pointer that we can return to user code, and allows us
            // to reconstruct the needed frame information in `handle_miri_resolve_frame`.
            // Note that we never actually read or write anything from/to this pointer -
            // all of the data is represented by the pointer value itself.
            let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance));
            fn_ptr.offset = Size::from_bytes(pos.0);
            Scalar::Ptr(fn_ptr)
        }).collect();

        let len = ptrs.len();

        let ptr_ty = tcx.mk_ptr(TypeAndMut {
            ty: tcx.types.unit,
            mutbl: Mutability::Mut
        });

        let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap());

        // Write pointers into array
        let alloc = this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into());
        for (i, ptr) in ptrs.into_iter().enumerate() {
            let place = this.mplace_index(alloc, i as u64)?;
            this.write_immediate_to_mplace(ptr.into(), place)?;
        }

        this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?;
        Ok(())
    }

    fn handle_miri_resolve_frame(
        &mut self,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();
        let tcx = this.tcx;
        let &[ptr, flags] = check_arg_count(args)?;

        let flags = this.read_scalar(flags)?.to_u64()?;
        if flags != 0 {
            throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags);
        }

        let ptr = match this.read_scalar(ptr)?.check_init()? {
            Scalar::Ptr(ptr) => ptr,
            Scalar::Raw { .. } => throw_ub_format!("expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr)
        };

        let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) {
            instance
        } else {
            throw_ub_format!("expected function pointer, found {:?}", ptr);
        };

        // Reconstruct the original function pointer,
        // which we pass to user code.
        let mut fn_ptr = ptr;
        fn_ptr.offset = Size::from_bytes(0);
        let fn_ptr = Scalar::Ptr(fn_ptr);

        let num_fields = dest.layout.layout.fields.count();

        if num_fields != 4 && num_fields != 5 {
            // Always mention 5 fields, since the 4-field struct is only supported
            // for backwards compatiblity. New code should declare 5 fields
            throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 5 fields");
        }

        let pos = BytePos(ptr.offset.bytes().try_into().unwrap());
        let name = fn_instance.to_string();

        let lo = tcx.sess.source_map().lookup_char_pos(pos);

        let filename = lo.file.name.to_string();
        let lineno: u32 = lo.line as u32;
        // `lo.col` is 0-based - add 1 to make it 1-based for the caller.
        let colno: u32 = lo.col.0 as u32 + 1;

        let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into());
        let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into());
        let lineno_alloc = Scalar::from_u32(lineno);
        let colno_alloc = Scalar::from_u32(colno);

        let dest = this.force_allocation(dest)?;
        if let ty::Adt(adt, _) = dest.layout.ty.kind() {
            if !adt.repr.c() {
                throw_ub_format!("miri_resolve_frame must be declared with a `#[repr(C)]` return type");
            }
        }

        this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?;
        this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?;
        this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?;
        this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?;

        if num_fields == 5 {
            this.write_scalar(fn_ptr, this.mplace_field(dest, 4)?.into())?;
        }

        Ok(())
    }
}
<commit_msg>Apply suggestions from code review<commit_after>use crate::*;
use helpers::check_arg_count;
use rustc_middle::ty::{self, TypeAndMut};
use rustc_ast::ast::Mutability;
use rustc_span::BytePos;
use rustc_target::abi::Size;
use std::convert::TryInto as _;
use crate::rustc_target::abi::LayoutOf as _;

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {

    fn handle_miri_get_backtrace(
        &mut self,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();
        let tcx = this.tcx;
        let &[flags] = check_arg_count(args)?;

        let flags = this.read_scalar(flags)?.to_u64()?;
        if flags != 0 {
            throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags);
        }

        let mut data = Vec::new();
        for frame in this.active_thread_stack().iter().rev() {
            let mut span = frame.current_span();
            // Match the behavior of runtime backtrace spans
            // by using a non-macro span in our backtrace. See `FunctionCx::debug_loc`.
            if span.from_expansion() && !tcx.sess.opts.debugging_opts.debug_macros {
                span = rustc_span::hygiene::walk_chain(span, frame.body.span.ctxt())
            }
            data.push((frame.instance, span.lo()));
        }

        let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| {
            // We represent a frame pointer by using the `span.lo` value
            // as an offset into the function's allocation. This gives us an
            // opaque pointer that we can return to user code, and allows us
            // to reconstruct the needed frame information in `handle_miri_resolve_frame`.
            // Note that we never actually read or write anything from/to this pointer -
            // all of the data is represented by the pointer value itself.
            let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance));
            fn_ptr.offset = Size::from_bytes(pos.0);
            Scalar::Ptr(fn_ptr)
        }).collect();

        let len = ptrs.len();

        let ptr_ty = tcx.mk_ptr(TypeAndMut {
            ty: tcx.types.unit,
            mutbl: Mutability::Mut
        });

        let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap());

        // Write pointers into array
        let alloc = this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into());
        for (i, ptr) in ptrs.into_iter().enumerate() {
            let place = this.mplace_index(alloc, i as u64)?;
            this.write_immediate_to_mplace(ptr.into(), place)?;
        }

        this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?;
        Ok(())
    }

    fn handle_miri_resolve_frame(
        &mut self,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>
    ) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();
        let tcx = this.tcx;
        let &[ptr, flags] = check_arg_count(args)?;

        let flags = this.read_scalar(flags)?.to_u64()?;
        if flags != 0 {
            throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags);
        }

        let ptr = match this.read_scalar(ptr)?.check_init()? {
            Scalar::Ptr(ptr) => ptr,
            Scalar::Raw { .. } => throw_ub_format!("expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr)
        };

        let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) {
            instance
        } else {
            throw_ub_format!("expected function pointer, found {:?}", ptr);
        };

        // Reconstruct the original function pointer,
        // which we pass to user code.
        let mut fn_ptr = ptr;
        fn_ptr.offset = Size::from_bytes(0);
        let fn_ptr = Scalar::Ptr(fn_ptr);

        let num_fields = dest.layout.layout.fields.count();

        if !(4..=5).contains(&num_fields) {
            // Always mention 5 fields, since the 4-field struct is only supported
            // for backwards compatiblity. New code should declare 5 fields.
            throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 5 fields");
        }

        let pos = BytePos(ptr.offset.bytes().try_into().unwrap());
        let name = fn_instance.to_string();

        let lo = tcx.sess.source_map().lookup_char_pos(pos);

        let filename = lo.file.name.to_string();
        let lineno: u32 = lo.line as u32;
        // `lo.col` is 0-based - add 1 to make it 1-based for the caller.
        let colno: u32 = lo.col.0 as u32 + 1;

        let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into());
        let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into());
        let lineno_alloc = Scalar::from_u32(lineno);
        let colno_alloc = Scalar::from_u32(colno);

        let dest = this.force_allocation(dest)?;
        if let ty::Adt(adt, _) = dest.layout.ty.kind() {
            if !adt.repr.c() {
                throw_ub_format!("miri_resolve_frame must be declared with a `#[repr(C)]` return type");
            }
        }

        this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?;
        this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?;
        this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?;
        this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?;

        if num_fields == 5 {
            this.write_scalar(fn_ptr, this.mplace_field(dest, 4)?.into())?;
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use core::ops::Mul;
use core::num::Wrapping;
use {One, CheckedMul};

/// Binary operator for raising a value to a power.
pub trait Pow<RHS> {
    /// The result after applying the operator.
    type Output;

    /// Returns `self` to the power `rhs`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::Pow;
    /// assert_eq!(Pow::pow(10u32, 2u32), 100);
    /// ```
    fn pow(self, rhs: RHS) -> Self::Output;
}

macro_rules! pow_impl {
    ($t:ty) => {
        pow_impl!($t, u8);
        pow_impl!($t, usize);

        // FIXME: these should be possible
        // pow_impl!($t, u16);
        // pow_impl!($t, u32);
        // pow_impl!($t, u64);
    };
    ($t:ty, $rhs:ty) => {
        pow_impl!($t, $rhs, usize, pow);
    };
    ($t:ty, $rhs:ty, $desired_rhs:ty, $method:expr) => {
        impl Pow<$rhs> for $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: $rhs) -> $t {
                ($method)(self, <$desired_rhs>::from(rhs))
            }
        }

        impl<'a> Pow<&'a $rhs> for $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: &'a $rhs) -> $t {
                ($method)(self, <$desired_rhs>::from(*rhs))
            }
        }

        impl<'a> Pow<$rhs> for &'a $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: $rhs) -> $t {
                ($method)(*self, <$desired_rhs>::from(rhs))
            }
        }

        impl<'a, 'b> Pow<&'a $rhs> for &'b $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: &'a $rhs) -> $t {
                ($method)(*self, <$desired_rhs>::from(*rhs))
            }
        }
    };
}

pow_impl!(u8, u8, u32, u8::pow);
pow_impl!(u8, u16, u32, u8::pow);
pow_impl!(u8, u32, u32, u8::pow);
pow_impl!(u8, usize);
pow_impl!(i8, u8, u32, i8::pow);
pow_impl!(i8, u16, u32, i8::pow);
pow_impl!(i8, u32, u32, i8::pow);
pow_impl!(i8, usize);
pow_impl!(u16, u8, u32, u16::pow);
pow_impl!(u16, u16, u32, u16::pow);
pow_impl!(u16, u32, u32, u16::pow);
pow_impl!(u16, usize);
pow_impl!(i16, u8, u32, i16::pow);
pow_impl!(i16, u16, u32, i16::pow);
pow_impl!(i16, u32, u32, i16::pow);
pow_impl!(i16, usize);
pow_impl!(u32, u8, u32, u32::pow);
pow_impl!(u32, u16, u32, u32::pow);
pow_impl!(u32, u32, u32, u32::pow);
pow_impl!(u32, usize);
pow_impl!(i32, u8, u32, i32::pow);
pow_impl!(i32, u16, u32, i32::pow);
pow_impl!(i32, u32, u32, i32::pow);
pow_impl!(i32, usize);
pow_impl!(u64, u8, u32, u64::pow);
pow_impl!(u64, u16, u32, u64::pow);
pow_impl!(u64, u32, u32, u64::pow);
pow_impl!(u64, usize);
pow_impl!(i64, u8, u32, i64::pow);
pow_impl!(i64, u16, u32, i64::pow);
pow_impl!(i64, u32, u32, i64::pow);
pow_impl!(i64, usize);
pow_impl!(usize, u8, u32, usize::pow);
pow_impl!(usize, u16, u32, usize::pow);
pow_impl!(usize, u32, u32, usize::pow);
pow_impl!(usize, usize);
pow_impl!(isize, u8, u32, isize::pow);
pow_impl!(isize, u16, u32, isize::pow);
pow_impl!(isize, u32, u32, isize::pow);
pow_impl!(isize, usize);
pow_impl!(Wrapping<u8>);
pow_impl!(Wrapping<i8>);
pow_impl!(Wrapping<u16>);
pow_impl!(Wrapping<i16>);
pow_impl!(Wrapping<u32>);
pow_impl!(Wrapping<i32>);
pow_impl!(Wrapping<u64>);
pow_impl!(Wrapping<i64>);
pow_impl!(Wrapping<usize>);
pow_impl!(Wrapping<isize>);

// FIXME: these should be possible
// pow_impl!(u8, u64);
// pow_impl!(i16, u64);
// pow_impl!(i8, u64);
// pow_impl!(u16, u64);
// pow_impl!(u32, u64);
// pow_impl!(i32, u64);
// pow_impl!(u64, u64);
// pow_impl!(i64, u64);
// pow_impl!(usize, u64);
// pow_impl!(isize, u64);

#[cfg(feature = "std")]
mod float_impls {
    use super::Pow;

    pow_impl!(f32, i8, i32, f32::powi);
    pow_impl!(f32, u8, i32, f32::powi);
    pow_impl!(f32, i16, i32, f32::powi);
    pow_impl!(f32, u16, i32, f32::powi);
    pow_impl!(f32, i32, i32, f32::powi);
    pow_impl!(f64, i8, i32, f64::powi);
    pow_impl!(f64, u8, i32, f64::powi);
    pow_impl!(f64, i16, i32, f64::powi);
    pow_impl!(f64, u16, i32, f64::powi);
    pow_impl!(f64, i32, i32, f64::powi);
    pow_impl!(f32, f32, f32, f32::powf);
    pow_impl!(f64, f32, f64, f64::powf);
    pow_impl!(f64, f64, f64, f64::powf);
}

/// Raises a value to the power of exp, using exponentiation by squaring.
///
/// # Example
///
/// ```rust
/// use num_traits::pow;
///
/// assert_eq!(pow(2i8, 4), 16);
/// assert_eq!(pow(6u8, 3), 216);
/// ```
#[inline]
pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T {
    if exp == 0 { return T::one() }

    while exp & 1 == 0 {
        base = base.clone() * base;
        exp >>= 1;
    }
    if exp == 1 { return base }

    let mut acc = base.clone();
    while exp > 1 {
        exp >>= 1;
        base = base.clone() * base;
        if exp & 1 == 1 {
            acc = acc * base.clone();
        }
    }
    acc
}

/// Raises a value to the power of exp, returning `None` if an overflow occurred.
///
/// Otherwise same as the `pow` function.
///
/// # Example
///
/// ```rust
/// use num_traits::checked_pow;
///
/// assert_eq!(checked_pow(2i8, 4), Some(16));
/// assert_eq!(checked_pow(7i8, 8), None);
/// assert_eq!(checked_pow(7u32, 8), Some(5_764_801));
/// ```
#[inline]
pub fn checked_pow<T: Clone + One + CheckedMul>(mut base: T, mut exp: usize) -> Option<T> {
    if exp == 0 { return Some(T::one()) }

    macro_rules! optry {
        ( $ expr : expr ) => {
            if let Some(val) = $expr { val } else { return None }
        }
    }

    while exp & 1 == 0 {
        base = optry!(base.checked_mul(&base));
        exp >>= 1;
    }
    if exp == 1 { return Some(base) }

    let mut acc = base.clone();
    while exp > 1 {
        exp >>= 1;
        base = optry!(base.checked_mul(&base));
        if exp & 1 == 1 {
            acc = optry!(acc.checked_mul(&base));
        }
    }
    Some(acc)
}
<commit_msg>Added impls of `Pow` for `i128` and `u128`<commit_after>use core::ops::Mul;
use core::num::Wrapping;
use {One, CheckedMul};

/// Binary operator for raising a value to a power.
pub trait Pow<RHS> {
    /// The result after applying the operator.
    type Output;

    /// Returns `self` to the power `rhs`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::Pow;
    /// assert_eq!(Pow::pow(10u32, 2u32), 100);
    /// ```
    fn pow(self, rhs: RHS) -> Self::Output;
}

macro_rules! pow_impl {
    ($t:ty) => {
        pow_impl!($t, u8);
        pow_impl!($t, usize);

        // FIXME: these should be possible
        // pow_impl!($t, u16);
        // pow_impl!($t, u32);
        // pow_impl!($t, u64);
    };
    ($t:ty, $rhs:ty) => {
        pow_impl!($t, $rhs, usize, pow);
    };
    ($t:ty, $rhs:ty, $desired_rhs:ty, $method:expr) => {
        impl Pow<$rhs> for $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: $rhs) -> $t {
                ($method)(self, <$desired_rhs>::from(rhs))
            }
        }

        impl<'a> Pow<&'a $rhs> for $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: &'a $rhs) -> $t {
                ($method)(self, <$desired_rhs>::from(*rhs))
            }
        }

        impl<'a> Pow<$rhs> for &'a $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: $rhs) -> $t {
                ($method)(*self, <$desired_rhs>::from(rhs))
            }
        }

        impl<'a, 'b> Pow<&'a $rhs> for &'b $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: &'a $rhs) -> $t {
                ($method)(*self, <$desired_rhs>::from(*rhs))
            }
        }
    };
}

pow_impl!(u8, u8, u32, u8::pow);
pow_impl!(u8, u16, u32, u8::pow);
pow_impl!(u8, u32, u32, u8::pow);
pow_impl!(u8, usize);
pow_impl!(i8, u8, u32, i8::pow);
pow_impl!(i8, u16, u32, i8::pow);
pow_impl!(i8, u32, u32, i8::pow);
pow_impl!(i8, usize);
pow_impl!(u16, u8, u32, u16::pow);
pow_impl!(u16, u16, u32, u16::pow);
pow_impl!(u16, u32, u32, u16::pow);
pow_impl!(u16, usize);
pow_impl!(i16, u8, u32, i16::pow);
pow_impl!(i16, u16, u32, i16::pow);
pow_impl!(i16, u32, u32, i16::pow);
pow_impl!(i16, usize);
pow_impl!(u32, u8, u32, u32::pow);
pow_impl!(u32, u16, u32, u32::pow);
pow_impl!(u32, u32, u32, u32::pow);
pow_impl!(u32, usize);
pow_impl!(i32, u8, u32, i32::pow);
pow_impl!(i32, u16, u32, i32::pow);
pow_impl!(i32, u32, u32, i32::pow);
pow_impl!(i32, usize);
pow_impl!(u64, u8, u32, u64::pow);
pow_impl!(u64, u16, u32, u64::pow);
pow_impl!(u64, u32, u32, u64::pow);
pow_impl!(u64, usize);
pow_impl!(i64, u8, u32, i64::pow);
pow_impl!(i64, u16, u32, i64::pow);
pow_impl!(i64, u32, u32, i64::pow);
pow_impl!(i64, usize);

#[cfg(feature = "i128")]
pow_impl!(u128, u8, u32, u128::pow);
#[cfg(feature = "i128")]
pow_impl!(u128, u16, u32, u128::pow);
#[cfg(feature = "i128")]
pow_impl!(u128, u32, u32, u128::pow);
#[cfg(feature = "i128")]
pow_impl!(u128, u64, u64, u128::pow);
#[cfg(feature = "i128")]
pow_impl!(u128, usize);

#[cfg(feature = "i128")]
pow_impl!(i128, u8, u32, i128::pow);
#[cfg(feature = "i128")]
pow_impl!(i128, u16, u32, i128::pow);
#[cfg(feature = "i128")]
pow_impl!(i128, u32, u32, i128::pow);
#[cfg(feature = "i128")]
pow_impl!(i128, u64, u64, i128::pow);
#[cfg(feature = "i128")]
pow_impl!(i128, usize);

pow_impl!(usize, u8, u32, usize::pow);
pow_impl!(usize, u16, u32, usize::pow);
pow_impl!(usize, u32, u32, usize::pow);
pow_impl!(usize, usize);
pow_impl!(isize, u8, u32, isize::pow);
pow_impl!(isize, u16, u32, isize::pow);
pow_impl!(isize, u32, u32, isize::pow);
pow_impl!(isize, usize);
pow_impl!(Wrapping<u8>);
pow_impl!(Wrapping<i8>);
pow_impl!(Wrapping<u16>);
pow_impl!(Wrapping<i16>);
pow_impl!(Wrapping<u32>);
pow_impl!(Wrapping<i32>);
pow_impl!(Wrapping<u64>);
pow_impl!(Wrapping<i64>);
#[cfg(feature = "i128")]
pow_impl!(Wrapping<u128>);
#[cfg(feature = "i128")]
pow_impl!(Wrapping<i128>);
pow_impl!(Wrapping<usize>);
pow_impl!(Wrapping<isize>);

// FIXME: these should be possible
// pow_impl!(u8, u64);
// pow_impl!(i16, u64);
// pow_impl!(i8, u64);
// pow_impl!(u16, u64);
// pow_impl!(u32, u64);
// pow_impl!(i32, u64);
// pow_impl!(u64, u64);
// pow_impl!(i64, u64);
// pow_impl!(usize, u64);
// pow_impl!(isize, u64);

#[cfg(feature = "std")]
mod float_impls {
    use super::Pow;

    pow_impl!(f32, i8, i32, f32::powi);
    pow_impl!(f32, u8, i32, f32::powi);
    pow_impl!(f32, i16, i32, f32::powi);
    pow_impl!(f32, u16, i32, f32::powi);
    pow_impl!(f32, i32, i32, f32::powi);
    pow_impl!(f64, i8, i32, f64::powi);
    pow_impl!(f64, u8, i32, f64::powi);
    pow_impl!(f64, i16, i32, f64::powi);
    pow_impl!(f64, u16, i32, f64::powi);
    pow_impl!(f64, i32, i32, f64::powi);
    pow_impl!(f32, f32, f32, f32::powf);
    pow_impl!(f64, f32, f64, f64::powf);
    pow_impl!(f64, f64, f64, f64::powf);
}

/// Raises a value to the power of exp, using exponentiation by squaring.
///
/// # Example
///
/// ```rust
/// use num_traits::pow;
///
/// assert_eq!(pow(2i8, 4), 16);
/// assert_eq!(pow(6u8, 3), 216);
/// ```
#[inline]
pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T {
    if exp == 0 { return T::one() }

    while exp & 1 == 0 {
        base = base.clone() * base;
        exp >>= 1;
    }
    if exp == 1 { return base }

    let mut acc = base.clone();
    while exp > 1 {
        exp >>= 1;
        base = base.clone() * base;
        if exp & 1 == 1 {
            acc = acc * base.clone();
        }
    }
    acc
}

/// Raises a value to the power of exp, returning `None` if an overflow occurred.
///
/// Otherwise same as the `pow` function.
///
/// # Example
///
/// ```rust
/// use num_traits::checked_pow;
///
/// assert_eq!(checked_pow(2i8, 4), Some(16));
/// assert_eq!(checked_pow(7i8, 8), None);
/// assert_eq!(checked_pow(7u32, 8), Some(5_764_801));
/// ```
#[inline]
pub fn checked_pow<T: Clone + One + CheckedMul>(mut base: T, mut exp: usize) -> Option<T> {
    if exp == 0 { return Some(T::one()) }

    macro_rules! optry {
        ( $ expr : expr ) => {
            if let Some(val) = $expr { val } else { return None }
        }
    }

    while exp & 1 == 0 {
        base = optry!(base.checked_mul(&base));
        exp >>= 1;
    }
    if exp == 1 { return Some(base) }

    let mut acc = base.clone();
    while exp > 1 {
        exp >>= 1;
        base = optry!(base.checked_mul(&base));
        if exp & 1 == 1 {
            acc = optry!(acc.checked_mul(&base));
        }
    }
    Some(acc)
}
<|endoftext|>


<commit_before>/*extern crate hyper;
extern crate rustc_serialize;*/

//use std::io;
use std::io::Read;

use super::rustc_serialize::json;
use super::rustc_serialize::Decodable;

use super::hyper::Client;
use super::hyper::header::Connection;

static BASE_PATH: &'static str = "https://api.telegram.org/";

pub struct Bot {
    api_key: String
}

#[derive(RustcDecodable)]
struct _GetMeResult {
    id: i32,
    first_name: String,
    username: String
}

#[derive(RustcDecodable)]
pub struct GetMe {
    pub ok: bool,
    pub result: _GetMeResult
}

impl Bot {
    pub fn new(api_key: &str) -> Bot {
        Bot {
            api_key: api_key.to_string()
        }
    }

    pub fn get_me(&self) -> String {
        let path = format!("{}bot{}/getMe", BASE_PATH, self.api_key);
        let client = Client::new();
        let mut res = client.get(&path)
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        return body;
    }

    pub fn send_message(&self, chat_id: i32, text: String) -> String {
        let path = format!("{}bot{}/sendMessage?chat_id={}&text={}", BASE_PATH, self.api_key, chat_id, text);
        let client = Client::new();
        let mut res = client.get(&path)
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        return body;
    }
}<commit_msg>fix build<commit_after>/*extern crate hyper;
extern crate rustc_serialize;*/

//use std::io;
use std::io::Read;

use super::rustc_serialize::json;
use super::rustc_serialize::Decodable;

use super::hyper::Client;
use super::hyper::header::Connection;

static BASE_PATH: &'static str = "https://api.telegram.org/";

pub struct Bot {
    api_key: String
}

#[derive(RustcDecodable)]
struct GetMeResult {
    id: i32,
    first_name: String,
    username: String,
}

#[derive(RustcDecodable)]
pub struct GetMe {
    pub ok: bool,
    result: GetMeResult,
}

impl Bot {
    pub fn new(api_key: &str) -> Bot {
        Bot {
            api_key: api_key.to_string()
        }
    }

    pub fn get_me(&self) -> String {
        let path = format!("{}bot{}/getMe", BASE_PATH, self.api_key);
        let client = Client::new();
        let mut res = client.get(&path)
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        return body;
    }

    pub fn send_message(&self, chat_id: i32, text: String) -> String {
        let path = format!("{}bot{}/sendMessage?chat_id={}&text={}", BASE_PATH, self.api_key, chat_id, text);
        let client = Client::new();
        let mut res = client.get(&path)
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        return body;
    }
}
<|endoftext|>


<commit_before>use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT};
use serde::Deserialize;
use std::collections::HashMap;

#[derive(Deserialize, Debug)]
struct Basis {
    elements: HashMap<String, ElementInfo>,
}

#[derive(Deserialize, Debug)]
struct ElementInfo {
    electron_shells: Vec<Shell>,
}

#[derive(Deserialize, Debug)]
struct Shell {
    angular_momentum: Vec<usize>,
    exponents: Vec<String>,
}

pub fn ang_min_and_max(basis_set: &str, element: usize) -> (HashMap<usize, f64>, f64) {
    let mut headers = HeaderMap::new();
    headers.insert(USER_AGENT, HeaderValue::from_static("reqwest"));

    let url = format!(
        "http://basissetexchange.org/api/basis/{}/format/json?elements={}",
        basis_set.to_string(),
        element.to_string()
    );

    let resp = reqwest::blocking::Client::new()
        .get(&url)
        .headers(headers)
        .send()
        .unwrap()
        .json::<Basis>()
        .unwrap();

    let element = resp.elements.get(&element.to_string()).unwrap();

    let mut alpha_max = -std::f64::MAX;
    let mut alpha_min = HashMap::new();

    for shell in &element.electron_shells {
        let angular_momentum = shell.angular_momentum[0];
        for exponent_string in &shell.exponents {
            let exponent: f64 = exponent_string.parse().unwrap();
            if exponent > alpha_max {
                alpha_max = exponent;
            }
            let s = alpha_min.entry(angular_momentum).or_insert(std::f64::MAX);
            if &exponent < s {
                *s = exponent;
            }
        }
    }

    (alpha_min, alpha_max)
}
<commit_msg>simplification (thanks to Jez)<commit_after>use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT};
use serde::Deserialize;
use std::collections::HashMap;

#[derive(Deserialize, Debug)]
struct Basis {
    elements: HashMap<String, ElementInfo>,
}

#[derive(Deserialize, Debug)]
struct ElementInfo {
    electron_shells: Vec<Shell>,
}

#[derive(Deserialize, Debug)]
struct Shell {
    angular_momentum: Vec<usize>,
    exponents: Vec<String>,
}

pub fn ang_min_and_max(basis_set: &str, element: usize) -> (HashMap<usize, f64>, f64) {
    let mut headers = HeaderMap::new();
    headers.insert(USER_AGENT, HeaderValue::from_static("reqwest"));

    let url = format!(
        "http://basissetexchange.org/api/basis/{}/format/json?elements={}",
        basis_set, element,
    );

    let resp = reqwest::blocking::Client::new()
        .get(&url)
        .headers(headers)
        .send()
        .unwrap()
        .json::<Basis>()
        .unwrap();

    let element = resp.elements.get(&element.to_string()).unwrap();

    let mut alpha_max = -std::f64::MAX;
    let mut alpha_min = HashMap::new();

    for shell in &element.electron_shells {
        let angular_momentum = shell.angular_momentum[0];
        for exponent_string in &shell.exponents {
            let exponent: f64 = exponent_string.parse().unwrap();
            if exponent > alpha_max {
                alpha_max = exponent;
            }
            let s = alpha_min.entry(angular_momentum).or_insert(std::f64::MAX);
            if &exponent < s {
                *s = exponent;
            }
        }
    }

    (alpha_min, alpha_max)
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

use rustc::ty::TyCtxt;
use rustc::mir::repr::*;
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc_data_structures::indexed_vec::Idx;
use rustc::ty::VariantKind;

pub struct Deaggregator;

impl Pass for Deaggregator {}

impl<'tcx> MirPass<'tcx> for Deaggregator {
    fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                    source: MirSource, mir: &mut Mir<'tcx>) {
        let node_id = source.item_id();
        let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
        debug!("running on: {:?}", node_path);
        // we only run when mir_opt_level > 1
        match tcx.sess.opts.debugging_opts.mir_opt_level {
            Some(0) |
            Some(1) |
            None => { return; },
            _ => {}
        };

        // Do not trigger on constants.  Could be revised in future
        if let MirSource::Fn(_) = source {} else { return; }

        let mut curr: usize = 0;
        for bb in mir.basic_blocks_mut() {
            let idx = match get_aggregate_statement(curr, &bb.statements) {
                Some(idx) => idx,
                None => continue,
            };
            // do the replacement
            debug!("removing statement {:?}", idx);
            let src_info = bb.statements[idx].source_info;
            let suffix_stmts = bb.statements.split_off(idx+1);
            let orig_stmt = bb.statements.pop().unwrap();
            let StatementKind::Assign(ref lhs, ref rhs) = orig_stmt.kind;
            let (agg_kind, operands) = match rhs {
                &Rvalue::Aggregate(ref agg_kind, ref operands) => (agg_kind, operands),
                _ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs),
            };
            let (adt_def, variant, substs) = match agg_kind {
                &AggregateKind::Adt(adt_def, variant, substs) => (adt_def, variant, substs),
                _ => span_bug!(src_info.span, "expected struct, not {:?}", rhs),
            };
            let n = bb.statements.len();
            bb.statements.reserve(n + operands.len() + suffix_stmts.len());
            for (i, op) in operands.iter().enumerate() {
                let ref variant_def = adt_def.variants[variant];
                let ty = variant_def.fields[i].ty(tcx, substs);
                let rhs = Rvalue::Use(op.clone());

                // since we don't handle enums, we don't need a cast
                let lhs_cast = lhs.clone();

                // FIXME we cannot deaggregate enums issue: 35186

                let lhs_proj = Lvalue::Projection(Box::new(LvalueProjection {
                    base: lhs_cast,
                    elem: ProjectionElem::Field(Field::new(i), ty),
                }));
                let new_statement = Statement {
                    source_info: src_info,
                    kind: StatementKind::Assign(lhs_proj, rhs),
                };
                debug!("inserting: {:?} @ {:?}", new_statement, idx + i);
                bb.statements.push(new_statement);
            }
            curr = bb.statements.len();
            bb.statements.extend(suffix_stmts);
        }
    }
}

fn get_aggregate_statement<'a, 'tcx, 'b>(curr: usize,
                                         statements: &Vec<Statement<'tcx>>)
                                         -> Option<usize> {
    for i in curr..statements.len() {
        let ref statement = statements[i];
        let StatementKind::Assign(_, ref rhs) = statement.kind;
        if let &Rvalue::Aggregate(ref kind, ref operands) = rhs {
            if let &AggregateKind::Adt(adt_def, variant, _) = kind {
                if operands.len() > 0 { // don't deaggregate ()
                    if adt_def.variants.len() > 1 {
                        // only deaggrate structs for now
                        continue;
                    }
                    debug!("getting variant {:?}", variant);
                    debug!("for adt_def {:?}", adt_def);
                    let variant_def = &adt_def.variants[variant];
                    if variant_def.kind == VariantKind::Struct {
                        return Some(i);
                    }
                }
            }
        }
    };
    None
}
<commit_msg>add hashtag to emphasis its a gh issue<commit_after>// Copyright 2016 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.

use rustc::ty::TyCtxt;
use rustc::mir::repr::*;
use rustc::mir::transform::{MirPass, MirSource, Pass};
use rustc_data_structures::indexed_vec::Idx;
use rustc::ty::VariantKind;

pub struct Deaggregator;

impl Pass for Deaggregator {}

impl<'tcx> MirPass<'tcx> for Deaggregator {
    fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                    source: MirSource, mir: &mut Mir<'tcx>) {
        let node_id = source.item_id();
        let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id));
        debug!("running on: {:?}", node_path);
        // we only run when mir_opt_level > 1
        match tcx.sess.opts.debugging_opts.mir_opt_level {
            Some(0) |
            Some(1) |
            None => { return; },
            _ => {}
        };

        // Do not trigger on constants.  Could be revised in future
        if let MirSource::Fn(_) = source {} else { return; }

        let mut curr: usize = 0;
        for bb in mir.basic_blocks_mut() {
            let idx = match get_aggregate_statement(curr, &bb.statements) {
                Some(idx) => idx,
                None => continue,
            };
            // do the replacement
            debug!("removing statement {:?}", idx);
            let src_info = bb.statements[idx].source_info;
            let suffix_stmts = bb.statements.split_off(idx+1);
            let orig_stmt = bb.statements.pop().unwrap();
            let StatementKind::Assign(ref lhs, ref rhs) = orig_stmt.kind;
            let (agg_kind, operands) = match rhs {
                &Rvalue::Aggregate(ref agg_kind, ref operands) => (agg_kind, operands),
                _ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs),
            };
            let (adt_def, variant, substs) = match agg_kind {
                &AggregateKind::Adt(adt_def, variant, substs) => (adt_def, variant, substs),
                _ => span_bug!(src_info.span, "expected struct, not {:?}", rhs),
            };
            let n = bb.statements.len();
            bb.statements.reserve(n + operands.len() + suffix_stmts.len());
            for (i, op) in operands.iter().enumerate() {
                let ref variant_def = adt_def.variants[variant];
                let ty = variant_def.fields[i].ty(tcx, substs);
                let rhs = Rvalue::Use(op.clone());

                // since we don't handle enums, we don't need a cast
                let lhs_cast = lhs.clone();

                // FIXME we cannot deaggregate enums issue: #35186

                let lhs_proj = Lvalue::Projection(Box::new(LvalueProjection {
                    base: lhs_cast,
                    elem: ProjectionElem::Field(Field::new(i), ty),
                }));
                let new_statement = Statement {
                    source_info: src_info,
                    kind: StatementKind::Assign(lhs_proj, rhs),
                };
                debug!("inserting: {:?} @ {:?}", new_statement, idx + i);
                bb.statements.push(new_statement);
            }
            curr = bb.statements.len();
            bb.statements.extend(suffix_stmts);
        }
    }
}

fn get_aggregate_statement<'a, 'tcx, 'b>(curr: usize,
                                         statements: &Vec<Statement<'tcx>>)
                                         -> Option<usize> {
    for i in curr..statements.len() {
        let ref statement = statements[i];
        let StatementKind::Assign(_, ref rhs) = statement.kind;
        if let &Rvalue::Aggregate(ref kind, ref operands) = rhs {
            if let &AggregateKind::Adt(adt_def, variant, _) = kind {
                if operands.len() > 0 { // don't deaggregate ()
                    if adt_def.variants.len() > 1 {
                        // only deaggrate structs for now
                        continue;
                    }
                    debug!("getting variant {:?}", variant);
                    debug!("for adt_def {:?}", adt_def);
                    let variant_def = &adt_def.variants[variant];
                    if variant_def.kind == VariantKind::Struct {
                        return Some(i);
                    }
                }
            }
        }
    };
    None
}
<|endoftext|>