<commit_before>extern crate termion;
extern crate rand;

use std::io::{self, Read, Write};
use std::collections::{HashSet, HashMap};

use termion::{clear, cursor, style, color};
use termion::raw::IntoRawMode;
use termion::input::TermRead;
use termion::event::Key;
use rand::random;

struct Game<R, W: Write> {
    score: u32,
    grid: [u32; 16usize],
    bgs: HashMap<u32, color::Bg<color::Rgb>>,
    game_over: bool,
    stdin: R,
    stdout: W,
}

fn init<R: Read, W: Write>(stdin: R, mut stdout: W) {
    write!(stdout, "{}", clear::All).unwrap();

    let mut bgs: HashMap<u32, color::Bg<color::Rgb>> = HashMap::with_capacity(17);
    // Ref: http://www.rapidtables.com/web/color/RGB_Color.htm
    // should cover all..
    let colors = [
        color::Bg(color::Rgb(224, 224, 224)), color::Bg(color::Rgb(255, 229, 204)),
        color::Bg(color::Rgb(255, 153, 153)), color::Bg(color::Rgb(204, 255, 209)),
        color::Bg(color::Rgb(204, 255, 255)), color::Bg(color::Rgb(204, 229, 255)),
        color::Bg(color::Rgb(229, 255, 204)), color::Bg(color::Rgb(229, 204, 255)),
        color::Bg(color::Rgb(255, 153, 255)), color::Bg(color::Rgb(255, 204, 229)),
        color::Bg(color::Rgb(255, 255, 51)), color::Bg(color::Rgb(255, 178, 102)),
        color::Bg(color::Rgb(178, 255, 102)), color::Bg(color::Rgb(102, 255, 178)),
        color::Bg(color::Rgb(102, 178, 255)), color::Bg(color::Rgb(102, 102, 255)),
        color::Bg(color::Rgb(255, 0, 0)),
    ];
    bgs.insert(0u32, colors[0]);
    for i in 1..17 {
        bgs.insert(1u32<<i as u32, colors[i]);
    }

    let mut game = Game {
        score: 0,
        grid: [0u32; 16usize],
        bgs: bgs,
        game_over: false,
        stdin: stdin.keys(),
        stdout: stdout,
    };

    game.reset();
    game.start();
}

impl <R, W: Write> Drop for Game<R, W> {
    fn drop(&mut self) {
        write!(self.stdout, "{}{}{}", clear::All, style::Reset,
               cursor::Goto(1, 1)).unwrap();
    }
}

macro_rules! continue_if_game_over {
    ($game_over:ident) => (
        if $game_over {
            continue;
        }
    )
}

impl <R: Iterator<Item=Result<Key, std::io::Error>>, W: Write> Game<R, W> {
    fn pos(&self, x: i32, y: i32) -> usize {
        (x * 4 + y) as usize
    }

    fn get_by_pos(&self, x: i32, y: i32) -> u32 {
        self.grid[self.pos(x, y)]
    }

    fn set_by_pos(&mut self, x: i32, y: i32, val: u32) {
        self.grid[self.pos(x, y)] = val;
    }

    fn start(&mut self) {
        let mut game_over = false;
        let mut moved = false;
        loop {
            let b = self.stdin.next().unwrap().unwrap();
            match b {
                Key::Up | Key::Char('w') | Key::Char('k') => {
                    continue_if_game_over!(game_over);
                    moved = self.up();
                },
                Key::Right | Key::Char('d') | Key::Char('l') => {
                    continue_if_game_over!(game_over);
                    moved = self.right();
                },
                Key::Down | Key::Char('s') | Key::Char('j') => {
                    continue_if_game_over!(game_over);
                    moved = self.down();
                },
                Key::Left | Key::Char('a') | Key::Char('h') => {
                    continue_if_game_over!(game_over);
                    moved = self.left();
                },
                Key::Char('r') => {
                    self.restart();
                    return;
                },
                Key::Esc | Key::Char('q') => return,
                _ => continue,
            }

            if !moved || game_over {
                continue;
            }
            let full_filled = self.fill_up();
            self.draw();
            if full_filled && self.game_over() {
                game_over = true;
                self.pop_menu();
            }
        }
    }

    fn reset(&mut self) {
        for i in 0..16usize {
            self.grid[i] = 0u32;
        }
        self.score = 0u32;
        self.game_over = false;
        let idx1 = random::<u8>() as usize % 16usize;
        self.grid[idx1] = 2u32;
        loop {
            let idx2 = random::<u8>() as usize % 16usize;
            if idx1 != idx2 {
                self.grid[idx2] = 2u32;
                break;
            }
        }
        self.draw();
    }

    fn restart(&mut self) {
        self.reset();
        self.start();
    }

    fn fill_up(&mut self) -> bool {
        let mut holes = HashSet::new();
        for i in 0..16usize {
            if self.grid[i] == 0u32 {
                holes.insert(i);
            }
        }

        let len = holes.len();
        if len == 0 {
            return true;
        }
        for idx in holes.iter() {  // use HashSet's random feature directly..
            // self.grid[*idx] = 1u32 << (*idx as u32 % 2u32 + 1u32);  // whatever...
            let mut threhold = 222u8;
            if len <= 4 {
                threhold = 127u8;
            }
            if random::<u8>() <= threhold {
                self.grid[*idx] = 2u32;
            } else {
                self.grid[*idx] = 4u32;
            }
            break;
        }

        (len-1) == 0
    }

    fn game_over(&mut self) -> bool {
        for x in 0..4 {
            for y in 1..4 {
                if self.get_by_pos(x, y-1) == self.get_by_pos(x, y) {
                    return false;
                }
            }
        }
        for y in 0..4 {
            for x in 1..4 {
                if self.get_by_pos(x-1, y) == self.get_by_pos(x, y) {
                    return false;
                }
            }
        }
        return true;
    }

    fn bg(&self, n: u32) -> color::Bg<color::Rgb> {
        match self.bgs.get(&n) {
            Some(bg) => *bg,
            None => color::Bg(color::Rgb(255, 255, 255)),
        }
    }

    fn draw(&mut self) {
        write!(self.stdout, "{}", cursor::Goto(1, 1)).unwrap();

        // header
        let header_bg = color::Bg(color::Rgb(128, 128, 128));
        write!(self.stdout, " {}{:31}{}\n\r", header_bg, " ", style::Reset).unwrap();
        let score = self.score.to_string();
        write!(self.stdout, " {}{} SCORE: {}{:space$}{}\n\r", header_bg, style::Bold, score,
               " ", style::Reset, space=23-score.len()).unwrap();
        write!(self.stdout, " {}{:31}{}\n\r", header_bg, " ", style::Reset).unwrap();
        write!(self.stdout, " {:32}\n\r", " ").unwrap();

        // body
        for x in 0..4i32 {
            let mut up_line: String = String::new();
            let mut mid_line: String = String::new();
            let mut down_line: String = String::new();
            for y in 0..4i32 {
                let val = self.get_by_pos(x, y);
                let sval = val.to_string();
                let bg = self.bg(val);

                up_line.push_str(format!(" {}{:7}{}", bg, " ", style::Reset).as_str());
                if val == 0u32 {
                    mid_line.push_str(format!(" {}{:7}{}", bg, " ", style::Reset).as_str());
                } else {
                    let pad = (7 - sval.len()) / 2;
                    mid_line.push_str(
                        format!(" {}{:lpad$}{}{}{}{}{:rpad$}{}", bg, " ", color::Fg(color::Black),
                                sval, style::Reset, bg, " ", style::Reset,
                                lpad=pad, rpad=7-sval.len()-pad).as_str());
                }
                down_line.push_str(format!(" {}{:7}{}", bg, " ", style::Reset).as_str());
            }
            up_line.push_str("\n\r");
            mid_line.push_str("\n\r");
            down_line.push_str("\n\r");
            self.stdout.write(up_line.as_bytes()).unwrap();
            self.stdout.write(mid_line.as_bytes()).unwrap();
            self.stdout.write(down_line.as_bytes()).unwrap();
            self.stdout.write(format!("{:32}\n\r", " ").as_bytes()).unwrap();
        }
        self.stdout.flush().unwrap();
    }

    fn pop_menu(&mut self) {
        let bg = color::Bg(color::Rgb(128, 128, 128));
        write!(self.stdout, "{}{}{}  GAME OVER!   {}\n\r",
               cursor::Goto(10, 4), bg, style::Bold, style::Reset).unwrap();
        write!(self.stdout, "{}{}  restart: r   {}\n\r",
               cursor::Goto(10, 5), bg, style::Reset).unwrap();
        write!(self.stdout, "{}{}  quit: ESC|q  {}\n\r",
               cursor::Goto(10, 6), bg, style::Reset).unwrap();
        write!(self.stdout, "{}{}               {}\n\r",
               cursor::Goto(10, 7), bg, style::Reset).unwrap();
    }

    fn merge<Fget, Fset>(&mut self, xs: [i32; 4], ys: [i32; 4],
                         mut fget: Fget, mut fset: Fset) -> bool
        where Fget: FnMut(&Game<R, W>, i32, i32) -> u32, Fset: FnMut(&mut Game<R, W>, i32, i32, u32) {
        let mut moved = false;  // Fuck: https://github.com/rust-lang/rust/issues/28570

        for x in xs.iter() {
            let mut prev_non_zero_y = ys[0];
            let first_y = ys[0];
            for y in (&ys[1..4]).iter() {
                let mut val = fget(self, *x, *y);
                if val != 0u32 {
                    if prev_non_zero_y < *y && fget(self, *x, prev_non_zero_y) == val {
                        let score = val * 2;
                        self.score += score;
                        fset(self, *x, prev_non_zero_y, score);
                        val = 0u32;
                        fset(self, *x, *y, val);
                        prev_non_zero_y = *y + 1;
                        moved = true;
                    } else {
                        prev_non_zero_y = *y;
                    }
                }

                let mut k = *y;
                while k > first_y {
                    let prev = fget(self, *x, k-1);
                    if prev != 0u32 || val == 0u32 {
                        break;
                    }
                    moved = true;
                    fset(self, *x, k-1, val);
                    fset(self, *x, k, 0u32);
                    k -= 1;
                    prev_non_zero_y = k;
                }
            }
        }

        moved
    }

    fn up(&mut self) -> bool {
        let fget = |g: &Game<R, W>, x: i32, y: i32| g.get_by_pos(y, x);
        let fset = |g: &mut Game<R, W>, x: i32, y: i32, val: u32| g.set_by_pos(y, x, val);
        let xs = [0, 1, 2, 3];
        let ys = [0, 1, 2, 3];
        return self.merge(xs, ys, fget, fset);
    }

    fn right(&mut self) -> bool {
        let fget = |g: &Game<R, W>, x: i32, y: i32| g.get_by_pos(-x, -y);
        let fset = |g: &mut Game<R, W>, x: i32, y: i32, val: u32| g.set_by_pos(-x, -y, val);
        let xs = [-3, -2, -1, 0];
        let ys = [-3, -2, -1, 0];
        return self.merge(xs, ys, fget, fset);
    }

    fn down(&mut self) -> bool {
        let fget = |g: &Game<R, W>, x: i32, y: i32| g.get_by_pos(-y, -x);
        let fset = |g: &mut Game<R, W>, x: i32, y: i32, val: u32| g.set_by_pos(-y, -x, val);
        let xs = [-3, -2, -1, 0];
        let ys = [-3, -2, -1, 0];
        return self.merge(xs, ys, fget, fset);
    }

    fn left(&mut self) -> bool {
        let fget = |g: &Game<R, W>, x: i32, y: i32| g.get_by_pos(x, y);
        let fset = |g: &mut Game<R, W>, x: i32, y: i32, val: u32| g.set_by_pos(x, y, val);
        let xs = [0, 1, 2, 3];
        let ys = [0, 1, 2, 3];
        return self.merge(xs, ys, fget, fset);
    }
}

fn main() {
    let stdout = io::stdout();
    let stdout = stdout.lock();
    let stdout = stdout.into_raw_mode().unwrap();
    let stdin = io::stdin();
    let stdin = stdin.lock();
    let stderr = io::stderr();
    let mut stderr = stderr.lock();

    let termsize = termion::terminal_size().ok();
    let (termwidth, termheight) = termsize.map(|(w, h)| (w-2, h-2)).unwrap();
    if termwidth < 32 || termheight < 20 {
        write!(stderr, "{}{}terminal size must satisfy with (width >= 32, height >= 20){}",
            style::Bold, color::Fg(color::Red), style::Reset).unwrap();
    } else {
        init(stdin, stdout);
    }
}
<commit_msg>remove unused member<commit_after>extern crate termion;
extern crate rand;

use std::io::{self, Read, Write};
use std::collections::{HashSet, HashMap};

use termion::{clear, cursor, style, color};
use termion::raw::IntoRawMode;
use termion::input::TermRead;
use termion::event::Key;
use rand::random;

struct Game<R, W: Write> {
    score: u32,
    grid: [u32; 16usize],
    bgs: HashMap<u32, color::Bg<color::Rgb>>,
    stdin: R,
    stdout: W,
}

fn init<R: Read, W: Write>(stdin: R, mut stdout: W) {
    write!(stdout, "{}", clear::All).unwrap();

    let mut bgs: HashMap<u32, color::Bg<color::Rgb>> = HashMap::with_capacity(17);
    // Ref: http://www.rapidtables.com/web/color/RGB_Color.htm
    // should cover all..
    let colors = [
        color::Bg(color::Rgb(224, 224, 224)), color::Bg(color::Rgb(255, 229, 204)),
        color::Bg(color::Rgb(255, 153, 153)), color::Bg(color::Rgb(204, 255, 209)),
        color::Bg(color::Rgb(204, 255, 255)), color::Bg(color::Rgb(204, 229, 255)),
        color::Bg(color::Rgb(229, 255, 204)), color::Bg(color::Rgb(229, 204, 255)),
        color::Bg(color::Rgb(255, 153, 255)), color::Bg(color::Rgb(255, 204, 229)),
        color::Bg(color::Rgb(255, 255, 51)), color::Bg(color::Rgb(255, 178, 102)),
        color::Bg(color::Rgb(178, 255, 102)), color::Bg(color::Rgb(102, 255, 178)),
        color::Bg(color::Rgb(102, 178, 255)), color::Bg(color::Rgb(102, 102, 255)),
        color::Bg(color::Rgb(255, 0, 0)),
    ];
    bgs.insert(0u32, colors[0]);
    for i in 1..17 {
        bgs.insert(1u32<<i as u32, colors[i]);
    }

    let mut game = Game {
        score: 0,
        grid: [0u32; 16usize],
        bgs: bgs,
        stdin: stdin.keys(),
        stdout: stdout,
    };

    game.reset();
    game.start();
}

impl <R, W: Write> Drop for Game<R, W> {
    fn drop(&mut self) {
        write!(self.stdout, "{}{}{}", clear::All, style::Reset,
               cursor::Goto(1, 1)).unwrap();
    }
}

macro_rules! continue_if_game_over {
    ($game_over:ident) => (
        if $game_over {
            continue;
        }
    )
}

impl <R: Iterator<Item=Result<Key, std::io::Error>>, W: Write> Game<R, W> {
    fn pos(&self, x: i32, y: i32) -> usize {
        (x * 4 + y) as usize
    }

    fn get_by_pos(&self, x: i32, y: i32) -> u32 {
        self.grid[self.pos(x, y)]
    }

    fn set_by_pos(&mut self, x: i32, y: i32, val: u32) {
        self.grid[self.pos(x, y)] = val;
    }

    fn start(&mut self) {
        let mut game_over = false;
        let mut moved = false;
        loop {
            let b = self.stdin.next().unwrap().unwrap();
            match b {
                Key::Up | Key::Char('w') | Key::Char('k') => {
                    continue_if_game_over!(game_over);
                    moved = self.up();
                },
                Key::Right | Key::Char('d') | Key::Char('l') => {
                    continue_if_game_over!(game_over);
                    moved = self.right();
                },
                Key::Down | Key::Char('s') | Key::Char('j') => {
                    continue_if_game_over!(game_over);
                    moved = self.down();
                },
                Key::Left | Key::Char('a') | Key::Char('h') => {
                    continue_if_game_over!(game_over);
                    moved = self.left();
                },
                Key::Char('r') => {
                    self.restart();
                    return;
                },
                Key::Esc | Key::Char('q') => return,
                _ => continue,
            }

            if !moved || game_over {
                continue;
            }
            let full_filled = self.fill_up();
            self.draw();
            if full_filled && self.game_over() {
                game_over = true;
                self.pop_menu();
            }
        }
    }

    fn reset(&mut self) {
        for i in 0..16usize {
            self.grid[i] = 0u32;
        }
        self.score = 0u32;
        self.game_over = false;
        let idx1 = random::<u8>() as usize % 16usize;
        self.grid[idx1] = 2u32;
        loop {
            let idx2 = random::<u8>() as usize % 16usize;
            if idx1 != idx2 {
                self.grid[idx2] = 2u32;
                break;
            }
        }
        self.draw();
    }

    fn restart(&mut self) {
        self.reset();
        self.start();
    }

    fn fill_up(&mut self) -> bool {
        let mut holes = HashSet::new();
        for i in 0..16usize {
            if self.grid[i] == 0u32 {
                holes.insert(i);
            }
        }

        let len = holes.len();
        if len == 0 {
            return true;
        }
        for idx in holes.iter() {  // use HashSet's random feature directly..
            // self.grid[*idx] = 1u32 << (*idx as u32 % 2u32 + 1u32);  // whatever...
            let mut threhold = 222u8;
            if len <= 4 {
                threhold = 127u8;
            }
            if random::<u8>() <= threhold {
                self.grid[*idx] = 2u32;
            } else {
                self.grid[*idx] = 4u32;
            }
            break;
        }

        (len-1) == 0
    }

    fn game_over(&mut self) -> bool {
        for x in 0..4 {
            for y in 1..4 {
                if self.get_by_pos(x, y-1) == self.get_by_pos(x, y) {
                    return false;
                }
            }
        }
        for y in 0..4 {
            for x in 1..4 {
                if self.get_by_pos(x-1, y) == self.get_by_pos(x, y) {
                    return false;
                }
            }
        }
        return true;
    }

    fn bg(&self, n: u32) -> color::Bg<color::Rgb> {
        match self.bgs.get(&n) {
            Some(bg) => *bg,
            None => color::Bg(color::Rgb(255, 255, 255)),
        }
    }

    fn draw(&mut self) {
        write!(self.stdout, "{}", cursor::Goto(1, 1)).unwrap();

        // header
        let header_bg = color::Bg(color::Rgb(128, 128, 128));
        write!(self.stdout, " {}{:31}{}\n\r", header_bg, " ", style::Reset).unwrap();
        let score = self.score.to_string();
        write!(self.stdout, " {}{} SCORE: {}{:space$}{}\n\r", header_bg, style::Bold, score,
               " ", style::Reset, space=23-score.len()).unwrap();
        write!(self.stdout, " {}{:31}{}\n\r", header_bg, " ", style::Reset).unwrap();
        write!(self.stdout, " {:32}\n\r", " ").unwrap();

        // body
        for x in 0..4i32 {
            let mut up_line: String = String::new();
            let mut mid_line: String = String::new();
            let mut down_line: String = String::new();
            for y in 0..4i32 {
                let val = self.get_by_pos(x, y);
                let sval = val.to_string();
                let bg = self.bg(val);

                up_line.push_str(format!(" {}{:7}{}", bg, " ", style::Reset).as_str());
                if val == 0u32 {
                    mid_line.push_str(format!(" {}{:7}{}", bg, " ", style::Reset).as_str());
                } else {
                    let pad = (7 - sval.len()) / 2;
                    mid_line.push_str(
                        format!(" {}{:lpad$}{}{}{}{}{:rpad$}{}", bg, " ", color::Fg(color::Black),
                                sval, style::Reset, bg, " ", style::Reset,
                                lpad=pad, rpad=7-sval.len()-pad).as_str());
                }
                down_line.push_str(format!(" {}{:7}{}", bg, " ", style::Reset).as_str());
            }
            up_line.push_str("\n\r");
            mid_line.push_str("\n\r");
            down_line.push_str("\n\r");
            self.stdout.write(up_line.as_bytes()).unwrap();
            self.stdout.write(mid_line.as_bytes()).unwrap();
            self.stdout.write(down_line.as_bytes()).unwrap();
            self.stdout.write(format!("{:32}\n\r", " ").as_bytes()).unwrap();
        }
        self.stdout.flush().unwrap();
    }

    fn pop_menu(&mut self) {
        let bg = color::Bg(color::Rgb(128, 128, 128));
        write!(self.stdout, "{}{}{}  GAME OVER!   {}\n\r",
               cursor::Goto(10, 4), bg, style::Bold, style::Reset).unwrap();
        write!(self.stdout, "{}{}  restart: r   {}\n\r",
               cursor::Goto(10, 5), bg, style::Reset).unwrap();
        write!(self.stdout, "{}{}  quit: ESC|q  {}\n\r",
               cursor::Goto(10, 6), bg, style::Reset).unwrap();
        write!(self.stdout, "{}{}               {}\n\r",
               cursor::Goto(10, 7), bg, style::Reset).unwrap();
    }

    fn merge<Fget, Fset>(&mut self, xs: [i32; 4], ys: [i32; 4],
                         mut fget: Fget, mut fset: Fset) -> bool
        where Fget: FnMut(&Game<R, W>, i32, i32) -> u32, Fset: FnMut(&mut Game<R, W>, i32, i32, u32) {
        let mut moved = false;  // Fuck: https://github.com/rust-lang/rust/issues/28570

        for x in xs.iter() {
            let mut prev_non_zero_y = ys[0];
            let first_y = ys[0];
            for y in (&ys[1..4]).iter() {
                let mut val = fget(self, *x, *y);
                if val != 0u32 {
                    if prev_non_zero_y < *y && fget(self, *x, prev_non_zero_y) == val {
                        let score = val * 2;
                        self.score += score;
                        fset(self, *x, prev_non_zero_y, score);
                        val = 0u32;
                        fset(self, *x, *y, val);
                        prev_non_zero_y = *y + 1;
                        moved = true;
                    } else {
                        prev_non_zero_y = *y;
                    }
                }

                let mut k = *y;
                while k > first_y {
                    let prev = fget(self, *x, k-1);
                    if prev != 0u32 || val == 0u32 {
                        break;
                    }
                    moved = true;
                    fset(self, *x, k-1, val);
                    fset(self, *x, k, 0u32);
                    k -= 1;
                    prev_non_zero_y = k;
                }
            }
        }

        moved
    }

    fn up(&mut self) -> bool {
        let fget = |g: &Game<R, W>, x: i32, y: i32| g.get_by_pos(y, x);
        let fset = |g: &mut Game<R, W>, x: i32, y: i32, val: u32| g.set_by_pos(y, x, val);
        let xs = [0, 1, 2, 3];
        let ys = [0, 1, 2, 3];
        return self.merge(xs, ys, fget, fset);
    }

    fn right(&mut self) -> bool {
        let fget = |g: &Game<R, W>, x: i32, y: i32| g.get_by_pos(-x, -y);
        let fset = |g: &mut Game<R, W>, x: i32, y: i32, val: u32| g.set_by_pos(-x, -y, val);
        let xs = [-3, -2, -1, 0];
        let ys = [-3, -2, -1, 0];
        return self.merge(xs, ys, fget, fset);
    }

    fn down(&mut self) -> bool {
        let fget = |g: &Game<R, W>, x: i32, y: i32| g.get_by_pos(-y, -x);
        let fset = |g: &mut Game<R, W>, x: i32, y: i32, val: u32| g.set_by_pos(-y, -x, val);
        let xs = [-3, -2, -1, 0];
        let ys = [-3, -2, -1, 0];
        return self.merge(xs, ys, fget, fset);
    }

    fn left(&mut self) -> bool {
        let fget = |g: &Game<R, W>, x: i32, y: i32| g.get_by_pos(x, y);
        let fset = |g: &mut Game<R, W>, x: i32, y: i32, val: u32| g.set_by_pos(x, y, val);
        let xs = [0, 1, 2, 3];
        let ys = [0, 1, 2, 3];
        return self.merge(xs, ys, fget, fset);
    }
}

fn main() {
    let stdout = io::stdout();
    let stdout = stdout.lock();
    let stdout = stdout.into_raw_mode().unwrap();
    let stdin = io::stdin();
    let stdin = stdin.lock();
    let stderr = io::stderr();
    let mut stderr = stderr.lock();

    let termsize = termion::terminal_size().ok();
    let (termwidth, termheight) = termsize.map(|(w, h)| (w-2, h-2)).unwrap();
    if termwidth < 32 || termheight < 20 {
        write!(stderr, "{}{}terminal size must satisfy with (width >= 32, height >= 20){}",
            style::Bold, color::Fg(color::Red), style::Reset).unwrap();
    } else {
        init(stdin, stdout);
    }
}
<|endoftext|>


<commit_before>//! Graph algorithms.
//!
//! It is a goal to gradually migrate the algorithms to be based on graph traits
//! so that they are generally applicable. For now, most of these use only the
//! **Graph** type.

use std::collections::BinaryHeap;

use super::{
    Graph,
    Directed,
    Undirected,
    EdgeType,
    Outgoing,
    Incoming,
    Dfs,
    MinScored,
};
use super::visit::{
    Reversed,
    Visitable,
    VisitMap,
};
use super::unionfind::UnionFind;
use super::graph::{
    NodeIndex,
    IndexType,
};

pub use super::isomorphism::is_isomorphic;
pub use super::dijkstra::dijkstra;

/// Return **true** if the input graph contains a cycle.
///
/// Treat the input graph as undirected.
pub fn is_cyclic_undirected<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>) -> bool where
    Ty: EdgeType,
    Ix: IndexType,
{
    let mut edge_sets = UnionFind::new(g.node_count());
    for edge in g.raw_edges().iter() {
        let (a, b) = (edge.source(), edge.target());

        // union the two vertices of the edge
        //  -- if they were already the same, then we have a cycle
        if !edge_sets.union(a.index(), b.index()) {
            return true
        }
    }
    false
}

/// **Deprecated: Renamed to *is_cyclic_undirected* **.
pub fn is_cyclic<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>) -> bool where
    Ty: EdgeType,
    Ix: IndexType,
{
    is_cyclic_undirected(g)
}

/// Check if a directed graph contains cycles.
///
/// Using the topological sort algorithm.
///
/// Return **true** if the graph had a cycle.
pub fn is_cyclic_directed<N, E, Ix>(g: &Graph<N, E, Directed, Ix>) -> bool where
    Ix: IndexType,
{
    let mut n_ordered = 0;
    let mut ordered = g.visit_map();
    let mut tovisit = Vec::new();

    // find all initial nodes
    tovisit.extend(g.without_edges(Incoming));

    // No initials means that it is a complete cycle.
    if tovisit.len() == 0 && g.node_count() != 0 {
        return true
    }

    while let Some(nix) = tovisit.pop() {
        if ordered.is_visited(&nix) {
            continue;
        }
        n_ordered += 1;
        ordered.visit(nix);
        for neigh in g.neighbors_directed(nix, Outgoing) {
            // Look at each neighbor, and those that only have incoming edges
            // from the already ordered list, they are the next to visit.
            if g.neighbors_directed(neigh, Incoming).all(|b| ordered.is_visited(&b)) {
                tovisit.push(neigh);
            }
        }
    }
    n_ordered != g.node_count()
}

/// Perform a topological sort of a directed graph.
///
/// Return a vector of nodes in topological order: each node is ordered
/// before its successors.
///
/// If the returned vec contains less than all the nodes of the graph, then
/// the graph was cyclic.
pub fn toposort<N, E, Ix>(g: &Graph<N, E, Directed, Ix>) -> Vec<NodeIndex<Ix>> where
    Ix: IndexType,
{
    let mut order = Vec::with_capacity(g.node_count());
    let mut ordered = g.visit_map();
    let mut tovisit = Vec::new();

    // find all initial nodes
    tovisit.extend(g.without_edges(Incoming));

    // Take an unvisited element and
    while let Some(nix) = tovisit.pop() {
        if ordered.is_visited(&nix) {
            continue;
        }
        order.push(nix);
        ordered.visit(nix);
        for neigh in g.neighbors_directed(nix, Outgoing) {
            // Look at each neighbor, and those that only have incoming edges
            // from the already ordered list, they are the next to visit.
            if g.neighbors_directed(neigh, Incoming).all(|b| ordered.is_visited(&b)) {
                tovisit.push(neigh);
            }
        }
    }

    order
}

/// Compute *Strongly connected components* using Kosaraju's algorithm.
///
/// Return a vector where each element is an scc.
///
/// For an undirected graph, the sccs are simply the connected components.
pub fn scc<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>) -> Vec<Vec<NodeIndex<Ix>>> where
    Ty: EdgeType,
    Ix: IndexType,
{
    let mut dfs = Dfs::empty(g);

    // First phase, reverse dfs pass, compute finishing times.
    let mut finish_order = Vec::new();
    for index in (0..g.node_count()) {
        if dfs.discovered.is_visited(&NodeIndex::<Ix>::new(index)) {
            continue
        }
        // We want to order the vertices by finishing time --
        // so record when we see them, then reverse all we have seen in this DFS pass.
        let pass_start = finish_order.len();
        dfs.move_to(NodeIndex::new(index));
        while let Some(nx) = dfs.next(&Reversed(g)) {
            finish_order.push(nx);
        }
        finish_order[pass_start..].reverse();
    }

    dfs.discovered.clear();
    let mut sccs = Vec::new();

    // Second phase
    // Process in decreasing finishing time order
    for &nindex in finish_order.iter().rev() {
        if dfs.discovered.is_visited(&nindex) {
            continue;
        }
        // Move to the leader node.
        dfs.move_to(nindex);
        //let leader = nindex;
        let mut scc = Vec::new();
        while let Some(nx) = dfs.next(g) {
            scc.push(nx);
        }
        sccs.push(scc);
    }
    sccs
}

/// Return the number of connected components of the graph.
///
/// For a directed graph, this is the *weakly* connected components.
pub fn connected_components<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>) -> usize where
    Ty: EdgeType,
    Ix: IndexType,
{
    let mut vertex_sets = UnionFind::new(g.node_count());
    for edge in g.raw_edges().iter() {
        let (a, b) = (edge.source(), edge.target());

        // union the two vertices of the edge
        vertex_sets.union(a.index(), b.index());
    }
    let mut labels = vertex_sets.into_labeling();
    labels.sort();
    labels.dedup();
    labels.len()
}

/// Return a *Minimum Spanning Tree* of a graph.
///
/// Treat the input graph as undirected.
///
/// Using Kruskal's algorithm with runtime **O(|E| log |E|)**. We actually
/// return a minimum spanning forest, i.e. a minimum spanning tree for each connected
/// component of the graph.
///
/// The resulting graph has all the vertices of the input graph (with identical node indices),
/// and **|V| - c** edges, where **c** is the number of connected components in **g**.
pub fn min_spanning_tree<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>) -> Graph<N, E, Undirected, Ix> where
    N: Clone,
    E: Clone + PartialOrd,
    Ty: EdgeType,
    Ix: IndexType,
{
    if g.node_count() == 0 {
        return Graph::with_capacity(0, 0)
    }

    // Create a mst skeleton by copying all nodes
    let mut mst = Graph::with_capacity(g.node_count(), g.node_count() - 1);
    for node in g.raw_nodes().iter() {
        mst.add_node(node.weight.clone());
    }

    // Initially each vertex is its own disjoint subgraph, track the connectedness
    // of the pre-MST with a union & find datastructure.
    let mut subgraphs = UnionFind::new(g.node_count());

    let mut sort_edges = BinaryHeap::with_capacity(g.edge_count());
    for edge in g.raw_edges().iter() {
        sort_edges.push(MinScored(edge.weight.clone(), (edge.source(), edge.target())));
    }

    // Kruskal's algorithm.
    // Algorithm is this:
    //
    // 1. Create a pre-MST with all the vertices and no edges.
    // 2. Repeat:
    //
    //  a. Remove the shortest edge from the original graph.
    //  b. If the edge connects two disjoint trees in the pre-MST,
    //     add the edge.
    while let Some(MinScored(score, (a, b))) = sort_edges.pop() {
        // check if the edge would connect two disjoint parts
        if subgraphs.union(a.index(), b.index()) {
            mst.add_edge(a, b, score);
        }
    }

    debug_assert!(mst.node_count() == g.node_count());
    debug_assert!(mst.edge_count() < g.node_count());
    mst
}
<commit_msg>Re-use the topo sort algorithm implementation<commit_after>//! Graph algorithms.
//!
//! It is a goal to gradually migrate the algorithms to be based on graph traits
//! so that they are generally applicable. For now, most of these use only the
//! **Graph** type.

use std::collections::BinaryHeap;

use super::{
    Graph,
    Directed,
    Undirected,
    EdgeType,
    Outgoing,
    Incoming,
    Dfs,
    MinScored,
};
use super::visit::{
    Reversed,
    Visitable,
    VisitMap,
};
use super::unionfind::UnionFind;
use super::graph::{
    NodeIndex,
    IndexType,
};

pub use super::isomorphism::is_isomorphic;
pub use super::dijkstra::dijkstra;

/// Return **true** if the input graph contains a cycle.
///
/// Treat the input graph as undirected.
pub fn is_cyclic_undirected<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>) -> bool where
    Ty: EdgeType,
    Ix: IndexType,
{
    let mut edge_sets = UnionFind::new(g.node_count());
    for edge in g.raw_edges().iter() {
        let (a, b) = (edge.source(), edge.target());

        // union the two vertices of the edge
        //  -- if they were already the same, then we have a cycle
        if !edge_sets.union(a.index(), b.index()) {
            return true
        }
    }
    false
}

/// **Deprecated: Renamed to *is_cyclic_undirected*.**
pub fn is_cyclic<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>) -> bool where
    Ty: EdgeType,
    Ix: IndexType,
{
    is_cyclic_undirected(g)
}

/// Perform a topological sort of a directed graph.
///
/// Visit each node in order (if it is part of a topological order.
fn generic_toposort<N, E, Ix, F>(g: &Graph<N, E, Directed, Ix>,
                                 mut visit: F) where
    Ix: IndexType,
    F: FnMut(&NodeIndex<Ix>),
{
    let mut ordered = g.visit_map();
    let mut tovisit = Vec::new();

    // find all initial nodes
    tovisit.extend(g.without_edges(Incoming));

    // Take an unvisited element and find which of its neighbors are next
    while let Some(nix) = tovisit.pop() {
        if ordered.is_visited(&nix) {
            continue;
        }
        visit(&nix);
        ordered.visit(nix);
        for neigh in g.neighbors_directed(nix, Outgoing) {
            // Look at each neighbor, and those that only have incoming edges
            // from the already ordered list, they are the next to visit.
            if g.neighbors_directed(neigh, Incoming).all(|b| ordered.is_visited(&b)) {
                tovisit.push(neigh);
            }
        }
    }
}

/// Check if a directed graph contains cycles.
///
/// Using the topological sort algorithm.
///
/// Return **true** if the graph had a cycle.
pub fn is_cyclic_directed<N, E, Ix>(g: &Graph<N, E, Directed, Ix>) -> bool where
    Ix: IndexType,
{
    let mut n_ordered = 0;
    generic_toposort(g, |_| n_ordered += 1);
    n_ordered != g.node_count()
}

/// Perform a topological sort of a directed graph.
///
/// Return a vector of nodes in topological order: each node is ordered
/// before its successors.
///
/// If the returned vec contains less than all the nodes of the graph, then
/// the graph was cyclic.
pub fn toposort<N, E, Ix>(g: &Graph<N, E, Directed, Ix>) -> Vec<NodeIndex<Ix>> where
    Ix: IndexType,
{
    let mut order = Vec::with_capacity(g.node_count());
    generic_toposort(g, |&ix| order.push(ix));
    order
}

/// Compute *Strongly connected components* using Kosaraju's algorithm.
///
/// Return a vector where each element is an scc.
///
/// For an undirected graph, the sccs are simply the connected components.
pub fn scc<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>) -> Vec<Vec<NodeIndex<Ix>>> where
    Ty: EdgeType,
    Ix: IndexType,
{
    let mut dfs = Dfs::empty(g);

    // First phase, reverse dfs pass, compute finishing times.
    let mut finish_order = Vec::new();
    for index in (0..g.node_count()) {
        if dfs.discovered.is_visited(&NodeIndex::<Ix>::new(index)) {
            continue
        }
        // We want to order the vertices by finishing time --
        // so record when we see them, then reverse all we have seen in this DFS pass.
        let pass_start = finish_order.len();
        dfs.move_to(NodeIndex::new(index));
        while let Some(nx) = dfs.next(&Reversed(g)) {
            finish_order.push(nx);
        }
        finish_order[pass_start..].reverse();
    }

    dfs.discovered.clear();
    let mut sccs = Vec::new();

    // Second phase
    // Process in decreasing finishing time order
    for &nindex in finish_order.iter().rev() {
        if dfs.discovered.is_visited(&nindex) {
            continue;
        }
        // Move to the leader node.
        dfs.move_to(nindex);
        //let leader = nindex;
        let mut scc = Vec::new();
        while let Some(nx) = dfs.next(g) {
            scc.push(nx);
        }
        sccs.push(scc);
    }
    sccs
}

/// Return the number of connected components of the graph.
///
/// For a directed graph, this is the *weakly* connected components.
pub fn connected_components<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>) -> usize where
    Ty: EdgeType,
    Ix: IndexType,
{
    let mut vertex_sets = UnionFind::new(g.node_count());
    for edge in g.raw_edges().iter() {
        let (a, b) = (edge.source(), edge.target());

        // union the two vertices of the edge
        vertex_sets.union(a.index(), b.index());
    }
    let mut labels = vertex_sets.into_labeling();
    labels.sort();
    labels.dedup();
    labels.len()
}

/// Return a *Minimum Spanning Tree* of a graph.
///
/// Treat the input graph as undirected.
///
/// Using Kruskal's algorithm with runtime **O(|E| log |E|)**. We actually
/// return a minimum spanning forest, i.e. a minimum spanning tree for each connected
/// component of the graph.
///
/// The resulting graph has all the vertices of the input graph (with identical node indices),
/// and **|V| - c** edges, where **c** is the number of connected components in **g**.
pub fn min_spanning_tree<N, E, Ty, Ix>(g: &Graph<N, E, Ty, Ix>) -> Graph<N, E, Undirected, Ix> where
    N: Clone,
    E: Clone + PartialOrd,
    Ty: EdgeType,
    Ix: IndexType,
{
    if g.node_count() == 0 {
        return Graph::with_capacity(0, 0)
    }

    // Create a mst skeleton by copying all nodes
    let mut mst = Graph::with_capacity(g.node_count(), g.node_count() - 1);
    for node in g.raw_nodes().iter() {
        mst.add_node(node.weight.clone());
    }

    // Initially each vertex is its own disjoint subgraph, track the connectedness
    // of the pre-MST with a union & find datastructure.
    let mut subgraphs = UnionFind::new(g.node_count());

    let mut sort_edges = BinaryHeap::with_capacity(g.edge_count());
    for edge in g.raw_edges().iter() {
        sort_edges.push(MinScored(edge.weight.clone(), (edge.source(), edge.target())));
    }

    // Kruskal's algorithm.
    // Algorithm is this:
    //
    // 1. Create a pre-MST with all the vertices and no edges.
    // 2. Repeat:
    //
    //  a. Remove the shortest edge from the original graph.
    //  b. If the edge connects two disjoint trees in the pre-MST,
    //     add the edge.
    while let Some(MinScored(score, (a, b))) = sort_edges.pop() {
        // check if the edge would connect two disjoint parts
        if subgraphs.union(a.index(), b.index()) {
            mst.add_edge(a, b, score);
        }
    }

    debug_assert!(mst.node_count() == g.node_count());
    debug_assert!(mst.edge_count() < g.node_count());
    mst
}
<|endoftext|>


<commit_before>#![macro_escape]
use libc;

use Error;

macro_rules! call( ($p:path($($e:expr),*)) => (
    $p($(::call::convert(&$e)),*)
) )

macro_rules! try_call( ($($arg:tt)*) => ({
    try!(::call::try(call!($($arg)*)))
}) )

#[doc(hidden)]
pub trait Convert<T> {
    fn convert(&self) -> T;
}

pub fn convert<T, U: Convert<T>>(u: &U) -> T { u.convert() }

pub fn try(ret: libc::c_int) -> Result<libc::c_int, Error> {
    match ret {
        n if n < 0 => Err(last_error()),
        n => Ok(n),
    }
}

fn last_error() -> Error {
    // Apparently libgit2 isn't necessarily guaranteed to set the last error
    // whenever a function returns a negative value!
    Error::last_error().unwrap_or_else(|| {
        Error::from_str("an unknown error occurred")
    })
}

mod impls {
    use std::c_str::CString;
    use libc;

    use raw;
    use call::Convert;

    macro_rules! primitive( ($($p:ident)*) => (
        $(impl Convert<$p> for $p { fn convert(&self) -> $p { *self } })*
    ) )

    primitive!(i8 i16 i32 i64 int u8 u16 u32 u64 uint)

    macro_rules! peel(
        ($macro:ident, ) => ();
        ($macro:ident, $_a:ident $($arg:ident)*) => ($macro!($($arg)*))
    )

    macro_rules! externfn( ($($arg:ident)*) => (
        impl<R $(,$arg)*> Convert<extern fn($($arg),*) -> R>
            for extern fn($($arg),*) -> R
        {
            fn convert(&self) -> extern fn($($arg),*) -> R { *self }
        }
        impl<R $(,$arg)*> Convert<Option<extern fn($($arg),*) -> R>>
            for Option<extern fn($($arg),*) -> R>
        {
            fn convert(&self) -> Option<extern fn($($arg),*) -> R> { *self }
        }
        peel!(externfn, $($arg)*)
    ) )
    externfn!(A B C D E F G)

    impl Convert<libc::c_int> for bool {
        fn convert(&self) -> libc::c_int { *self as libc::c_int }
    }
    impl<T> Convert<*const T> for *const T {
        fn convert(&self) -> *const T { *self }
    }
    impl<T> Convert<*mut T> for *mut T {
        fn convert(&self) -> *mut T { *self }
    }
    impl<'a, T> Convert<*const T> for &'a T {
        fn convert(&self) -> *const T { *self as *const T }
    }
    impl<'a, T> Convert<*mut T> for &'a mut T {
        fn convert(&self) -> *mut T { &**self as *const T as *mut T }
    }

    impl Convert<*const libc::c_char> for CString {
        fn convert(&self) -> *const libc::c_char { self.as_ptr() }
    }

    impl Convert<*const libc::c_char> for Option<CString> {
        fn convert(&self) -> *const libc::c_char {
            self.as_ref().map(|s| s.convert()).unwrap_or(0 as *const _)
        }
    }

    impl<'a, T> Convert<*const T> for Option<&'a T> {
        fn convert(&self) -> *const T {
            self.as_ref().map(|s| s.convert()).unwrap_or(0 as *const _)
        }
    }

    impl<'a, T> Convert<*mut T> for Option<&'a mut T> {
        fn convert(&self) -> *mut T {
            self.as_ref().map(|s| s.convert()).unwrap_or(0 as *mut _)
        }
    }

    impl Convert<raw::git_reset_t> for ::ResetType {
        fn convert(&self) -> raw::git_reset_t {
            match *self {
                ::Soft => raw::GIT_RESET_SOFT,
                ::Hard => raw::GIT_RESET_HARD,
                ::Mixed => raw::GIT_RESET_MIXED,
            }
        }
    }

    impl Convert<raw::git_direction> for ::Direction {
        fn convert(&self) -> raw::git_direction {
            match *self {
                ::DirPush => raw::GIT_DIRECTION_PUSH,
                ::DirFetch => raw::GIT_DIRECTION_FETCH,
            }
        }
    }

    impl Convert<raw::git_otype> for ::ObjectType {
        fn convert(&self) -> raw::git_otype {
            match *self {
                ::ObjectAny => raw::GIT_OBJ_ANY,
                ::ObjectCommit => raw::GIT_OBJ_COMMIT,
                ::ObjectTree => raw::GIT_OBJ_TREE,
                ::ObjectBlob => raw::GIT_OBJ_BLOB,
                ::ObjectTag => raw::GIT_OBJ_TAG,
            }
        }
    }

    impl Convert<raw::git_otype> for Option<::ObjectType> {
        fn convert(&self) -> raw::git_otype {
            self.unwrap_or(::ObjectAny).convert()
        }
    }

    impl Convert<raw::git_branch_t> for ::BranchType {
        fn convert(&self) -> raw::git_branch_t {
            match *self {
                ::BranchRemote => raw::GIT_BRANCH_REMOTE,
                ::BranchLocal => raw::GIT_BRANCH_LOCAL,
            }
        }
    }

    impl Convert<raw::git_branch_t> for Option<::BranchType> {
        fn convert(&self) -> raw::git_branch_t {
            self.map(|s| s.convert()).unwrap_or(raw::GIT_BRANCH_ALL)
        }
    }

    impl Convert<raw::git_config_level_t> for ::ConfigLevel {
        fn convert(&self) -> raw::git_config_level_t {
            match *self {
                ::ConfigSystem => raw::GIT_CONFIG_LEVEL_SYSTEM,
                ::ConfigXDG => raw::GIT_CONFIG_LEVEL_XDG,
                ::ConfigGlobal => raw::GIT_CONFIG_LEVEL_GLOBAL,
                ::ConfigLocal => raw::GIT_CONFIG_LEVEL_LOCAL,
                ::ConfigApp => raw::GIT_CONFIG_LEVEL_APP,
                ::ConfigHighest => raw::GIT_CONFIG_HIGHEST_LEVEL,
            }
        }
    }
}
<commit_msg>Work around rust-lang/rust#18732<commit_after>#![macro_escape]
use libc;

use Error;

macro_rules! call( (raw::$p:ident ($($e:expr),*)) => (
    raw::$p($(::call::convert(&$e)),*)
) )

macro_rules! try_call( ($($arg:tt)*) => ({
    try!(::call::try(call!($($arg)*)))
}) )

#[doc(hidden)]
pub trait Convert<T> {
    fn convert(&self) -> T;
}

pub fn convert<T, U: Convert<T>>(u: &U) -> T { u.convert() }

pub fn try(ret: libc::c_int) -> Result<libc::c_int, Error> {
    match ret {
        n if n < 0 => Err(last_error()),
        n => Ok(n),
    }
}

fn last_error() -> Error {
    // Apparently libgit2 isn't necessarily guaranteed to set the last error
    // whenever a function returns a negative value!
    Error::last_error().unwrap_or_else(|| {
        Error::from_str("an unknown error occurred")
    })
}

mod impls {
    use std::c_str::CString;
    use libc;

    use raw;
    use call::Convert;

    macro_rules! primitive( ($($p:ident)*) => (
        $(impl Convert<$p> for $p { fn convert(&self) -> $p { *self } })*
    ) )

    primitive!(i8 i16 i32 i64 int u8 u16 u32 u64 uint)

    macro_rules! peel(
        ($macro:ident, ) => ();
        ($macro:ident, $_a:ident $($arg:ident)*) => ($macro!($($arg)*))
    )

    macro_rules! externfn( ($($arg:ident)*) => (
        impl<R $(,$arg)*> Convert<extern fn($($arg),*) -> R>
            for extern fn($($arg),*) -> R
        {
            fn convert(&self) -> extern fn($($arg),*) -> R { *self }
        }
        impl<R $(,$arg)*> Convert<Option<extern fn($($arg),*) -> R>>
            for Option<extern fn($($arg),*) -> R>
        {
            fn convert(&self) -> Option<extern fn($($arg),*) -> R> { *self }
        }
        peel!(externfn, $($arg)*)
    ) )
    externfn!(A B C D E F G)

    impl Convert<libc::c_int> for bool {
        fn convert(&self) -> libc::c_int { *self as libc::c_int }
    }
    impl<T> Convert<*const T> for *const T {
        fn convert(&self) -> *const T { *self }
    }
    impl<T> Convert<*mut T> for *mut T {
        fn convert(&self) -> *mut T { *self }
    }
    impl<'a, T> Convert<*const T> for &'a T {
        fn convert(&self) -> *const T { *self as *const T }
    }
    impl<'a, T> Convert<*mut T> for &'a mut T {
        fn convert(&self) -> *mut T { &**self as *const T as *mut T }
    }

    impl Convert<*const libc::c_char> for CString {
        fn convert(&self) -> *const libc::c_char { self.as_ptr() }
    }

    impl Convert<*const libc::c_char> for Option<CString> {
        fn convert(&self) -> *const libc::c_char {
            self.as_ref().map(|s| s.convert()).unwrap_or(0 as *const _)
        }
    }

    impl<'a, T> Convert<*const T> for Option<&'a T> {
        fn convert(&self) -> *const T {
            self.as_ref().map(|s| s.convert()).unwrap_or(0 as *const _)
        }
    }

    impl<'a, T> Convert<*mut T> for Option<&'a mut T> {
        fn convert(&self) -> *mut T {
            self.as_ref().map(|s| s.convert()).unwrap_or(0 as *mut _)
        }
    }

    impl Convert<raw::git_reset_t> for ::ResetType {
        fn convert(&self) -> raw::git_reset_t {
            match *self {
                ::Soft => raw::GIT_RESET_SOFT,
                ::Hard => raw::GIT_RESET_HARD,
                ::Mixed => raw::GIT_RESET_MIXED,
            }
        }
    }

    impl Convert<raw::git_direction> for ::Direction {
        fn convert(&self) -> raw::git_direction {
            match *self {
                ::DirPush => raw::GIT_DIRECTION_PUSH,
                ::DirFetch => raw::GIT_DIRECTION_FETCH,
            }
        }
    }

    impl Convert<raw::git_otype> for ::ObjectType {
        fn convert(&self) -> raw::git_otype {
            match *self {
                ::ObjectAny => raw::GIT_OBJ_ANY,
                ::ObjectCommit => raw::GIT_OBJ_COMMIT,
                ::ObjectTree => raw::GIT_OBJ_TREE,
                ::ObjectBlob => raw::GIT_OBJ_BLOB,
                ::ObjectTag => raw::GIT_OBJ_TAG,
            }
        }
    }

    impl Convert<raw::git_otype> for Option<::ObjectType> {
        fn convert(&self) -> raw::git_otype {
            self.unwrap_or(::ObjectAny).convert()
        }
    }

    impl Convert<raw::git_branch_t> for ::BranchType {
        fn convert(&self) -> raw::git_branch_t {
            match *self {
                ::BranchRemote => raw::GIT_BRANCH_REMOTE,
                ::BranchLocal => raw::GIT_BRANCH_LOCAL,
            }
        }
    }

    impl Convert<raw::git_branch_t> for Option<::BranchType> {
        fn convert(&self) -> raw::git_branch_t {
            self.map(|s| s.convert()).unwrap_or(raw::GIT_BRANCH_ALL)
        }
    }

    impl Convert<raw::git_config_level_t> for ::ConfigLevel {
        fn convert(&self) -> raw::git_config_level_t {
            match *self {
                ::ConfigSystem => raw::GIT_CONFIG_LEVEL_SYSTEM,
                ::ConfigXDG => raw::GIT_CONFIG_LEVEL_XDG,
                ::ConfigGlobal => raw::GIT_CONFIG_LEVEL_GLOBAL,
                ::ConfigLocal => raw::GIT_CONFIG_LEVEL_LOCAL,
                ::ConfigApp => raw::GIT_CONFIG_LEVEL_APP,
                ::ConfigHighest => raw::GIT_CONFIG_HIGHEST_LEVEL,
            }
        }
    }
}
<|endoftext|>


<commit_before>//! The `conf` module contains functions for loading and saving game
//! configurations.
//!
//! A `Conf` struct is used to specify hardware setup stuff used to create
//! the window and other context information.

use std::io;
use toml;

use GameResult;

/// Possible fullscreen modes.
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum FullscreenType {
    /// Windowed mode
    Off,
    /// Real fullscreen
    True,
    /// Windowed fullscreen, generally preferred over real fullscreen
    /// these days 'cause it plays nicer with multiple monitors.
    Desktop
}

use sdl2::video::FullscreenType as SdlFullscreenType;
impl From<SdlFullscreenType> for FullscreenType {
    fn from(other: SdlFullscreenType) -> Self {
        match other {
            SdlFullscreenType::Off => FullscreenType::Off,
            SdlFullscreenType::True => FullscreenType::True,
            SdlFullscreenType::Desktop => FullscreenType::Desktop,
        }
    }
}

impl From<FullscreenType> for SdlFullscreenType {
    fn from(other: FullscreenType) -> Self {
        match other {
            FullscreenType::Off => SdlFullscreenType::Off,
            FullscreenType::True => SdlFullscreenType::True,
            FullscreenType::Desktop => SdlFullscreenType::Desktop,
        }
    }

}

/// A builder structure containing flags for defining window settings.
///
/// Defaults:
///
/// ```rust,ignore
/// WindowMode {
///     borderless: false,
///     resizable: false,
///     fullscreen_type: FullscreenType::Off,
///     vsync: true,
///     min_dimensions: (0, 0),
///     max_dimensions: (0, 0),
/// }
/// ```
#[derive(Debug, Copy, Clone, SmartDefault, Serialize, Deserialize, PartialEq, Eq)]
pub struct WindowMode {
    /// Whether or not to show window decorations
    #[default = r#"false"#]
    pub borderless: bool,
    /// Whether or not the window is resizable
    #[default = r#"false"#]
    pub resizable: bool,
    /// Fullscreen type
    #[default = r#"FullscreenType::Off"#]
    pub fullscreen_type: FullscreenType,
    /// Whether or not to enable vsync
    #[default = r#"true"#]
    pub vsync: bool,
    /// Minimum width for resizable windows; 0 means no limit
    #[default = r#"0"#]
    pub min_width: u32,
    /// Minimum height for resizable windows; 0 means no limit
    #[default = r#"0"#]
    pub min_height: u32,
    /// Maximum width for resizable windows; 0 means no limit
    #[default = r#"0"#]
    pub max_width: u32,
    /// Maximum height for resizable windows; 0 means no limit
    #[default = r#"0"#]
    pub max_height: u32,
}

impl WindowMode {
    /// Set borderless
    pub fn borderless(mut self, borderless: bool) -> Self {
        self.borderless = borderless;
        self
    }

    /// Set the fullscreen type
    pub fn fullscreen_type(mut self, fullscreen_type: FullscreenType) -> Self {
        self.fullscreen_type = fullscreen_type;
        self
    }

    /// Set vsync
    pub fn vsync(mut self, vsync: bool) -> Self {
        self.vsync = vsync;
        self
    }

    /// Set minimum window dimensions for windowed mode
    pub fn min_dimensions(mut self, width: u32, height: u32) -> Self {
        self.min_width = width;
        self.min_height = height;
        self
    }

    /// Set maximum window dimensions for windowed mode
    pub fn max_dimensions(mut self, width: u32, height: u32) -> Self {
        self.max_width = width;
        self.max_height = height;
        self
    }
}

/// A structure containing configuration data
/// for the game engine.
///
/// Defaults:
///
/// ```rust,ignore
/// Conf {
///     window_title: "An easy, good game"
///     window_icon: ""
///     window_height: 600
///     window_width: 800
///     vsync: true
/// }
/// ```
#[derive(Serialize, Deserialize, Debug, PartialEq, SmartDefault)]
pub struct Conf {
    /// The window title.
    #[default = r#""An easy, good game".to_owned()"#]
    pub window_title: String,
    /// A file path to the window's icon.
    /// It is rooted in the `resources` directory (see the `filesystem` module for details),
    /// and an empty string results in a blank/default icon.
    #[default = r#""".to_owned()"#]
    pub window_icon: String,
    /// The window's height
    #[default = "600"]
    pub window_height: u32,
    /// The window's width
    #[default = "800"]
    pub window_width: u32,
    /// Window setting information
    pub window_mode: WindowMode,
}

impl Conf {
    /// Same as Conf::default()
    pub fn new() -> Self {
        Self::default()
    }

    /// Load a TOML file from the given `Read` and attempts to parse
    /// a `Conf` from it.
    pub fn from_toml_file<R: io::Read>(file: &mut R) -> GameResult<Conf> {
        let mut s = String::new();
        file.read_to_string(&mut s)?;
        let decoded = toml::from_str(&s)?;
        Ok(decoded)
    }

    /// Saves the `Conf` to the given `Write` object,
    /// formatted as TOML.
    pub fn to_toml_file<W: io::Write>(&self, file: &mut W) -> GameResult<()> {
        let s = toml::to_vec(self)?;
        file.write_all(&s)?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use conf;
    use serde_json;

    /// Tries to encode and decode a `Conf` object
    /// and makes sure it gets the same result it had.
    #[test]
    fn encode_round_trip() {
        let c1 = conf::Conf::new();
        let mut writer = Vec::new();
        let s = serde_json::to_string(&c1);
        println!("S is {:?}", s);
        let _c = c1.to_toml_file(&mut writer).unwrap();
        println!("{}", String::from_utf8_lossy(&writer));
        let mut reader = writer.as_slice();
        let c2 = conf::Conf::from_toml_file(&mut reader).unwrap();
        assert_eq!(c1, c2);
    }
}
<commit_msg>Fix tests I stupidly broke while debugging<commit_after>//! The `conf` module contains functions for loading and saving game
//! configurations.
//!
//! A `Conf` struct is used to specify hardware setup stuff used to create
//! the window and other context information.

use std::io;
use toml;

use GameResult;

/// Possible fullscreen modes.
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum FullscreenType {
    /// Windowed mode
    Off,
    /// Real fullscreen
    True,
    /// Windowed fullscreen, generally preferred over real fullscreen
    /// these days 'cause it plays nicer with multiple monitors.
    Desktop
}

use sdl2::video::FullscreenType as SdlFullscreenType;
impl From<SdlFullscreenType> for FullscreenType {
    fn from(other: SdlFullscreenType) -> Self {
        match other {
            SdlFullscreenType::Off => FullscreenType::Off,
            SdlFullscreenType::True => FullscreenType::True,
            SdlFullscreenType::Desktop => FullscreenType::Desktop,
        }
    }
}

impl From<FullscreenType> for SdlFullscreenType {
    fn from(other: FullscreenType) -> Self {
        match other {
            FullscreenType::Off => SdlFullscreenType::Off,
            FullscreenType::True => SdlFullscreenType::True,
            FullscreenType::Desktop => SdlFullscreenType::Desktop,
        }
    }

}

/// A builder structure containing flags for defining window settings.
///
/// Defaults:
///
/// ```rust,ignore
/// WindowMode {
///     borderless: false,
///     resizable: false,
///     fullscreen_type: FullscreenType::Off,
///     vsync: true,
///     min_dimensions: (0, 0),
///     max_dimensions: (0, 0),
/// }
/// ```
#[derive(Debug, Copy, Clone, SmartDefault, Serialize, Deserialize, PartialEq, Eq)]
pub struct WindowMode {
    /// Whether or not to show window decorations
    #[default = r#"false"#]
    pub borderless: bool,
    /// Whether or not the window is resizable
    #[default = r#"false"#]
    pub resizable: bool,
    /// Fullscreen type
    #[default = r#"FullscreenType::Off"#]
    pub fullscreen_type: FullscreenType,
    /// Whether or not to enable vsync
    #[default = r#"true"#]
    pub vsync: bool,
    /// Minimum width for resizable windows; 0 means no limit
    #[default = r#"0"#]
    pub min_width: u32,
    /// Minimum height for resizable windows; 0 means no limit
    #[default = r#"0"#]
    pub min_height: u32,
    /// Maximum width for resizable windows; 0 means no limit
    #[default = r#"0"#]
    pub max_width: u32,
    /// Maximum height for resizable windows; 0 means no limit
    #[default = r#"0"#]
    pub max_height: u32,
}

impl WindowMode {
    /// Set borderless
    pub fn borderless(mut self, borderless: bool) -> Self {
        self.borderless = borderless;
        self
    }

    /// Set the fullscreen type
    pub fn fullscreen_type(mut self, fullscreen_type: FullscreenType) -> Self {
        self.fullscreen_type = fullscreen_type;
        self
    }

    /// Set vsync
    pub fn vsync(mut self, vsync: bool) -> Self {
        self.vsync = vsync;
        self
    }

    /// Set minimum window dimensions for windowed mode
    pub fn min_dimensions(mut self, width: u32, height: u32) -> Self {
        self.min_width = width;
        self.min_height = height;
        self
    }

    /// Set maximum window dimensions for windowed mode
    pub fn max_dimensions(mut self, width: u32, height: u32) -> Self {
        self.max_width = width;
        self.max_height = height;
        self
    }
}

/// A structure containing configuration data
/// for the game engine.
///
/// Defaults:
///
/// ```rust,ignore
/// Conf {
///     window_title: "An easy, good game"
///     window_icon: ""
///     window_height: 600
///     window_width: 800
///     vsync: true
/// }
/// ```
#[derive(Serialize, Deserialize, Debug, PartialEq, SmartDefault)]
pub struct Conf {
    /// The window title.
    #[default = r#""An easy, good game".to_owned()"#]
    pub window_title: String,
    /// A file path to the window's icon.
    /// It is rooted in the `resources` directory (see the `filesystem` module for details),
    /// and an empty string results in a blank/default icon.
    #[default = r#""".to_owned()"#]
    pub window_icon: String,
    /// The window's height
    #[default = "600"]
    pub window_height: u32,
    /// The window's width
    #[default = "800"]
    pub window_width: u32,
    /// Window setting information
    pub window_mode: WindowMode,
}

impl Conf {
    /// Same as Conf::default()
    pub fn new() -> Self {
        Self::default()
    }

    /// Load a TOML file from the given `Read` and attempts to parse
    /// a `Conf` from it.
    pub fn from_toml_file<R: io::Read>(file: &mut R) -> GameResult<Conf> {
        let mut s = String::new();
        file.read_to_string(&mut s)?;
        let decoded = toml::from_str(&s)?;
        Ok(decoded)
    }

    /// Saves the `Conf` to the given `Write` object,
    /// formatted as TOML.
    pub fn to_toml_file<W: io::Write>(&self, file: &mut W) -> GameResult<()> {
        let s = toml::to_vec(self)?;
        file.write_all(&s)?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use conf;

    /// Tries to encode and decode a `Conf` object
    /// and makes sure it gets the same result it had.
    #[test]
    fn encode_round_trip() {
        let c1 = conf::Conf::new();
        let mut writer = Vec::new();
        let _c = c1.to_toml_file(&mut writer).unwrap();
        let mut reader = writer.as_slice();
        let c2 = conf::Conf::from_toml_file(&mut reader).unwrap();
        assert_eq!(c1, c2);
    }
}
<|endoftext|>


<commit_before>use ast::{Ast, AstTrait};
use token::{Token, TokenTrait, Type};
use builtins;
use std::cmp::Ordering;

pub struct Eval {
    ast: Ast,
    stack: Vec<(Ast, usize)>,
    evaluated: bool
}

pub trait EvalTrait {
    fn eval(&mut self);
    fn is_evaluated(&self) -> bool;
}

pub trait PrettyPrint {
    fn pretty_print(&mut self) -> String;
    fn push_whitespace(&self, pretty: &mut String);
}

impl PrettyPrint for Eval {
    fn push_whitespace(&self, pretty: &mut String) {
        for _ in 0..self.stack.len() {
            pretty.push('\t');
        }
    }

    fn pretty_print(&mut self) -> String {
        let mut pretty = String::new();
        loop {
            match self.stack.pop() {
                Some(mut current) => {
                    match current.0.get_child(0) {
                        Some(mut child) => {
                            self.stack.push(current);
                            if child.node_val.is_some() {
                                let tok = child.node_val.unwrap();
                                if tok.tok_type == Type::Oparen {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('(');
                                    pretty.push('\n');
                                } else if tok.tok_type == Type::OpenList {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('<');
                                    pretty.push('\n');
                                }
                                child.node_val = Some(tok);
                            }
                            self.stack.push((child, 0));
                        },
                        None => {
                            if current.0.node_val.is_some() {
                                let tok = current.0.node_val.unwrap();
                                self.push_whitespace(&mut pretty);
                                match tok.tok_type {
                                    Type::Oparen => pretty.push(')'),
                                    Type::OpenList => pretty.push('>'),
                                    _ => pretty.push_str(&tok.get_lexed())
                                }
                            }
                            pretty.push('\n');
                        }
                    }
                },
                None => {
                    match self.ast.get_child(0) {
                        Some(mut child) => {
                            if child.node_val.is_some() {
                                let tok = child.node_val.unwrap();
                                if tok.tok_type == Type::Oparen {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('(');
                                    pretty.push('\n');
                                } else if tok.tok_type == Type::OpenList {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('<');
                                    pretty.push('\n');
                                }
                                child.node_val = Some(tok);
                            }
                            self.stack.push((child, 0));
                        },
                        None => break
                    }
                }
            }
            if self.stack.is_empty() && self.ast.child_count() == 0 {
                break;
            }
        }
        pretty
    }
}

impl EvalTrait for Eval {
    fn eval(&mut self) {
        let mut scope = Scope::new_root();
        while !self.evaluated {
            scope = self.eval_node(scope); // If scope says evaluate, evaluate.
        }
    }

    fn is_evaluated(&self) -> bool {
        self.evaluated
    }
}

impl Eval {
    pub fn new(ast: Ast) -> Self {
        Eval {
            ast: ast,
            stack: Vec::new(),
            evaluated: false
        }
    }

    pub fn new_option(ast: Option<Ast>) -> Self {
        match ast {
            Some(tree) => Eval {
                ast: tree,
                stack: Vec::new(),
                evaluated: false
            },
            None => panic!()
        }
    }

    fn expand_function(&mut self, scope: &mut Scope) -> bool {
        match self.stack.pop() {
            Some(mut current) => {
                match current.0.is_function() {
                    true => {
                        match scope.find_func(&current.0.node_val.unwrap().get_lexed()) {
                            Some(ref func) => self.inject_params(func),
                            None => false
                        }
                    },
                    false => false
                }
            },
            None => false
        }
    }

    fn inject_params(&mut self, func: &Func) -> bool {
        match self.stack.pop() {
            Some(mut current) => {
                let mut current_children = current.0.dump_children();
                let func_children = func.params.clone_children();
                for child in func_children.into_iter() {
                    current.0.push_child(builtins::generate_set_ast(child.node_val.unwrap(), current_children.remove(0)));
                }
                current.0.push_child(func.body.clone());
                self.stack.push(current);
                true
            },
            None => false
        }
    }

    fn eval_node(&mut self, mut scope: Scope) -> Scope {
        match self.stack.pop() {
            Some(mut current) => {
                match current.0.get_child(0) {
                    Some(mut child) => {
                        self.stack.push(current);
                        if child.node_val.is_some() {
                            let tok = child.node_val.unwrap();
                            if tok.tok_type == Type::Func {
                                child.node_val = Some(tok);
                                self.stack.push((child, 0));
                                if !self.expand_function(&mut scope) {
                                    // evaluate the builtin, if it exists
                                }
                            } else {
                                child.node_val = Some(tok);
                                self.stack.push((child, 0));
                            }
                        } else {
                            self.stack.push((child, 0));
                        }
                    },
                    None => {
                        match self.stack.pop() {
                            Some(mut parent) => {
                                let new_index = current.1 + 1;
                                parent.0.insert_child(current.0, current.1);
                                if parent.0.child_count() > new_index {
                                    let new_child = parent.0.get_child(new_index);
                                    self.stack.push(parent);
                                    self.stack.push((new_child.unwrap(), new_index));
                                } else {
                                    self.stack.push(parent);
                                    scope.evaluate_scope = true;
                                }
                            },
                            None => self.evaluated = true
                        }
                    }
                }
            },
            None => {
                match self.ast.get_child(0) {
                    Some(mut child) => {
                        if child.node_val.is_some() {
                            let tok = child.node_val.unwrap();
                            if tok.tok_type == Type::Func {
                                child.node_val = Some(tok);
                                self.stack.push((child, 0));
                                if !self.expand_function(&mut scope) {
                                    // evaluate the builtin, if it exists
                                }
                            } else {
                                child.node_val = Some(tok);
                                self.stack.push((child, 0));
                            }
                        } else {
                            self.stack.push((child, 0));
                        }
                    },
                    None => self.evaluated = true
                }
            }
        }
        if self.stack.is_empty() && self.ast.child_count() == 0 {
            self.evaluated = true;
        }
        scope
    }
}

struct Scope {
    pub parent: Option<Box<Scope>>,
    funcs: Vec<Func>,
    in_builtin: bool,
    pub evaluate_scope: bool
}

impl Scope {
    pub fn new(parent: Scope) -> Self
    {
        Scope {
            parent: Some(Box::new(parent)),
            funcs: Vec::new(),
            in_builtin: false,
            evaluate_scope: false
        }
    }

    pub fn new_root() -> Self {
        Scope {
            parent: None,
            funcs: Vec::new(),
            in_builtin: false,
            evaluate_scope: false
        }
    }

    pub fn insert_func(&mut self, func: Func) {
        if self.find_func(func.get_name()).is_none() {
            let loc = self.funcs.binary_search(&func);
            if loc.is_err() {
                self.funcs.insert(loc.unwrap(), func);
            }
        }
    }

    pub fn find_func(&mut self, tok_str: &String) -> Option<Func> {
        let loc = self.funcs.binary_search_by(|func| {
            tok_str.cmp(func.get_name())
        });
        match loc {
            Ok(index) => Some(self.funcs.remove(index)),
            _ => {
                match self.parent {
                    Some(ref mut parent) => parent.find_func(tok_str),
                    None => None
                }
            }
        }
    }
}

struct Func {
    name: String,
    pub body: Ast,
    pub params: Ast
}

impl Func {
    pub fn new(name: String, body: Ast, params: Ast) -> Self {
        Func {
            name: name,
            body: body,
            params: params
        }
    }

    pub fn get_name(&self) -> &String {
        &self.name
    }
}

impl Ord for Func {
    fn cmp(&self, other: &Func) -> Ordering {
        self.name.cmp(other.get_name())
    }
}

impl PartialOrd for Func {
    fn partial_cmp(&self, other: &Func) -> Option<Ordering> {
        self.name.partial_cmp(other.get_name())
    }
}

impl Eq for Func { }

impl PartialEq for Func {
    fn eq(&self, other: &Func) -> bool {
        self.name.eq(other.get_name())
    }

    fn ne(&self, other: &Func) -> bool {
        self.name.ne(other.get_name())
    }
}
<commit_msg>fixed mistake<commit_after>use ast::{Ast, AstTrait};
use token::{Token, TokenTrait, Type};
use builtins;
use std::cmp::Ordering;

pub struct Eval {
    ast: Ast,
    stack: Vec<(Ast, usize)>,
    evaluated: bool
}

pub trait EvalTrait {
    fn eval(&mut self);
    fn is_evaluated(&self) -> bool;
}

pub trait PrettyPrint {
    fn pretty_print(&mut self) -> String;
    fn push_whitespace(&self, pretty: &mut String);
}

impl PrettyPrint for Eval {
    fn push_whitespace(&self, pretty: &mut String) {
        for _ in 0..self.stack.len() {
            pretty.push('\t');
        }
    }

    fn pretty_print(&mut self) -> String {
        let mut pretty = String::new();
        loop {
            match self.stack.pop() {
                Some(mut current) => {
                    match current.0.get_child(0) {
                        Some(mut child) => {
                            self.stack.push(current);
                            if child.node_val.is_some() {
                                let tok = child.node_val.unwrap();
                                if tok.tok_type == Type::Oparen {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('(');
                                    pretty.push('\n');
                                } else if tok.tok_type == Type::OpenList {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('<');
                                    pretty.push('\n');
                                }
                                child.node_val = Some(tok);
                            }
                            self.stack.push((child, 0));
                        },
                        None => {
                            if current.0.node_val.is_some() {
                                let tok = current.0.node_val.unwrap();
                                self.push_whitespace(&mut pretty);
                                match tok.tok_type {
                                    Type::Oparen => pretty.push(')'),
                                    Type::OpenList => pretty.push('>'),
                                    _ => pretty.push_str(&tok.get_lexed())
                                }
                            }
                            pretty.push('\n');
                        }
                    }
                },
                None => {
                    match self.ast.get_child(0) {
                        Some(mut child) => {
                            if child.node_val.is_some() {
                                let tok = child.node_val.unwrap();
                                if tok.tok_type == Type::Oparen {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('(');
                                    pretty.push('\n');
                                } else if tok.tok_type == Type::OpenList {
                                    self.push_whitespace(&mut pretty);
                                    pretty.push('<');
                                    pretty.push('\n');
                                }
                                child.node_val = Some(tok);
                            }
                            self.stack.push((child, 0));
                        },
                        None => break
                    }
                }
            }
            if self.stack.is_empty() && self.ast.child_count() == 0 {
                break;
            }
        }
        pretty
    }
}

impl EvalTrait for Eval {
    fn eval(&mut self) {
        let mut scope = Scope::new_root();
        while !self.evaluated {
            scope = self.eval_node(scope); // If scope says evaluate, evaluate.
        }
    }

    fn is_evaluated(&self) -> bool {
        self.evaluated
    }
}

impl Eval {
    pub fn new(ast: Ast) -> Self {
        Eval {
            ast: ast,
            stack: Vec::new(),
            evaluated: false
        }
    }

    pub fn new_option(ast: Option<Ast>) -> Self {
        match ast {
            Some(tree) => Eval {
                ast: tree,
                stack: Vec::new(),
                evaluated: false
            },
            None => panic!()
        }
    }

    fn expand_function(&mut self, scope: &mut Scope) -> bool {
        match self.stack.pop() {
            Some(mut current) => {
                match current.0.is_function() {
                    true => {
                        match scope.find_func(&current.0.node_val.unwrap().get_lexed()) {
                            Some(ref func) => self.inject_params(func),
                            None => false
                        }
                    },
                    false => {
                        self.stack.push(current);
                        false
                    }
                }
            },
            None => false
        }
    }

    fn inject_params(&mut self, func: &Func) -> bool {
        match self.stack.pop() {
            Some(mut current) => {
                let mut current_children = current.0.dump_children();
                let func_children = func.params.clone_children();
                for child in func_children.into_iter() {
                    current.0.push_child(builtins::generate_set_ast(child.node_val.unwrap(), current_children.remove(0)));
                }
                current.0.push_child(func.body.clone());
                self.stack.push(current);
                true
            },
            None => false
        }
    }

    fn eval_node(&mut self, mut scope: Scope) -> Scope {
        match self.stack.pop() {
            Some(mut current) => {
                match current.0.get_child(0) {
                    Some(mut child) => {
                        self.stack.push(current);
                        if child.node_val.is_some() {
                            let tok = child.node_val.unwrap();
                            if tok.tok_type == Type::Func {
                                child.node_val = Some(tok);
                                self.stack.push((child, 0));
                                if !self.expand_function(&mut scope) {
                                    // evaluate the builtin, if it exists
                                }
                            } else {
                                child.node_val = Some(tok);
                                self.stack.push((child, 0));
                            }
                        } else {
                            self.stack.push((child, 0));
                        }
                    },
                    None => {
                        match self.stack.pop() {
                            Some(mut parent) => {
                                let new_index = current.1 + 1;
                                parent.0.insert_child(current.0, current.1);
                                if parent.0.child_count() > new_index {
                                    let new_child = parent.0.get_child(new_index);
                                    self.stack.push(parent);
                                    self.stack.push((new_child.unwrap(), new_index));
                                } else {
                                    self.stack.push(parent);
                                    scope.evaluate_scope = true;
                                }
                            },
                            None => self.evaluated = true
                        }
                    }
                }
            },
            None => {
                match self.ast.get_child(0) {
                    Some(mut child) => {
                        if child.node_val.is_some() {
                            let tok = child.node_val.unwrap();
                            if tok.tok_type == Type::Func {
                                child.node_val = Some(tok);
                                self.stack.push((child, 0));
                                if !self.expand_function(&mut scope) {
                                    // evaluate the builtin, if it exists
                                }
                            } else {
                                child.node_val = Some(tok);
                                self.stack.push((child, 0));
                            }
                        } else {
                            self.stack.push((child, 0));
                        }
                    },
                    None => self.evaluated = true
                }
            }
        }
        if self.stack.is_empty() && self.ast.child_count() == 0 {
            self.evaluated = true;
        }
        scope
    }
}

struct Scope {
    pub parent: Option<Box<Scope>>,
    funcs: Vec<Func>,
    in_builtin: bool,
    pub evaluate_scope: bool
}

impl Scope {
    pub fn new(parent: Scope) -> Self
    {
        Scope {
            parent: Some(Box::new(parent)),
            funcs: Vec::new(),
            in_builtin: false,
            evaluate_scope: false
        }
    }

    pub fn new_root() -> Self {
        Scope {
            parent: None,
            funcs: Vec::new(),
            in_builtin: false,
            evaluate_scope: false
        }
    }

    pub fn insert_func(&mut self, func: Func) {
        if self.find_func(func.get_name()).is_none() {
            let loc = self.funcs.binary_search(&func);
            if loc.is_err() {
                self.funcs.insert(loc.unwrap(), func);
            }
        }
    }

    pub fn find_func(&mut self, tok_str: &String) -> Option<Func> {
        let loc = self.funcs.binary_search_by(|func| {
            tok_str.cmp(func.get_name())
        });
        match loc {
            Ok(index) => Some(self.funcs.remove(index)),
            _ => {
                match self.parent {
                    Some(ref mut parent) => parent.find_func(tok_str),
                    None => None
                }
            }
        }
    }
}

struct Func {
    name: String,
    pub body: Ast,
    pub params: Ast
}

impl Func {
    pub fn new(name: String, body: Ast, params: Ast) -> Self {
        Func {
            name: name,
            body: body,
            params: params
        }
    }

    pub fn get_name(&self) -> &String {
        &self.name
    }
}

impl Ord for Func {
    fn cmp(&self, other: &Func) -> Ordering {
        self.name.cmp(other.get_name())
    }
}

impl PartialOrd for Func {
    fn partial_cmp(&self, other: &Func) -> Option<Ordering> {
        self.name.partial_cmp(other.get_name())
    }
}

impl Eq for Func { }

impl PartialEq for Func {
    fn eq(&self, other: &Func) -> bool {
        self.name.eq(other.get_name())
    }

    fn ne(&self, other: &Func) -> bool {
        self.name.ne(other.get_name())
    }
}
<|endoftext|>


<commit_before>use std::collections::VecMap;
use ast:: {
    Value,
        NumberValue,
        VectorValue,
};
use resolve::context::{ValueID};

#[deriving(PartialEq, Show)]
pub enum ValueSrc {
    ConstSlice(Vec<Value>),
    DynElem(ValueID),
    DynSlice(ValueID, uint),
}

#[deriving(PartialEq, Show)]
pub enum ValOp {
    ConstOp(Value),
    CheckOp(ValueID, Value),
    RangeCheckOp(ValueID, f64, f64),

    ChooseOp(ValueID, Vec<(Value, Value)>),

    SliceOp(ValueID, /*offset*/ uint, /*length*/ uint),
    ElemOp(ValueID, uint),
    ConcatOp(Vec<ValueSrc>),

    BinaryOp(ValueID, BinOp, ValueID),
    BinaryConstOp(ValueID, BinOp, f64),
}

impl ValOp {
    pub fn each_dep(&self, f: |ValueID| -> ()) {
        match *self {
            ConstOp(..) => (),
            CheckOp(i, _) => f(i),
            RangeCheckOp(i, _, _) => f(i),
            ChooseOp(i, _) => f(i),
            SliceOp(i, _, _) => f(i),
            ElemOp(i, _) => f(i),
            ConcatOp(ref l) => {
                for src in l.iter() {
                    match *src {
                        ConstSlice(..) => (),
                        DynElem(i) => f(i),
                        DynSlice(i, _) => f(i)
                    }
                }
            }
            BinaryOp(l, _, r) => { f(l); f(r) }
            BinaryConstOp(i, _, _) => f(i),
        }
    }

    pub fn all_deps(&self, f: |ValueID| -> bool) -> bool {
        let mut r = true;
        self.each_dep(|id| r &= f(id));
        r
    }
}

/// Binary numeric operators
#[deriving(PartialEq, Eq, Show)]
pub enum BinOp {
    BiAdd,       // a + b
    BiSub,       // a - b
    BiSubSwap,   // b - a

    BiMul,       // a * b
    BiDiv,       // a / b
    BiDivSwap,   // b / a
}

impl BinOp {
    /// a `op` b
    pub fn eval(&self, a: f64, b: f64) -> f64 {
        match *self {
            BiAdd     => a + b,
            BiSub     => a - b,
            BiSubSwap => b - a,
            BiMul     => a * b,
            BiDiv     => a / b,
            BiDivSwap => b / a,
        }
    }

    /// (a `op` b) == (b `op.swap()` a)
    pub fn swap(&self) -> BinOp {
        match *self {
            BiAdd     => BiAdd,
            BiSub     => BiSubSwap,
            BiSubSwap => BiSub,
            BiMul     => BiMul,
            BiDiv     => BiDivSwap,
            BiDivSwap => BiDiv,
        }
    }

    /// ((a `op` b) `op.invert()` b) == a
    pub fn invert(&self) -> BinOp {
        match *self {
            BiAdd     => BiSub,
            BiSub     => BiAdd,
            BiSubSwap => BiSubSwap,
            BiMul     => BiDiv,
            BiDiv     => BiMul,
            BiDivSwap => BiDivSwap,
        }
    }
}

#[deriving(Show)]
pub struct Ops {
    pub entry: Vec<(ValueID, ValOp)>,
    pub exit: Vec<(ValueID, ValOp)>,
}

impl Ops {
    pub fn new() -> Ops { Ops{ entry: Vec::new(), exit: Vec::new() } }
    pub fn count(&self) -> uint { self.entry.len() + self.exit.len() }
}

pub struct State {
    registers: VecMap<Value>,
}

impl State {
    pub fn new() -> State {
        let mut s = State {
            registers: VecMap::new()
        };
        // TODO: shouldn't be necessary (we currently read from 0 on ignores)
        s.registers.insert(0, ::ast::SymbolValue("invalid".to_string()));
        s
    }

    pub fn get(&self, reg: ValueID) -> &Value {
        debug!("get {}: {}", reg, self.registers.find(&reg));
        &self.registers[reg]
    }

    pub fn set(&mut self, reg: ValueID, v: Value) -> bool {
        debug!("set {}: {}", reg, v);
        // TODO: should assert the register is not already set, once exec doesn't run things twice
        self.registers.insert(reg, v);
        true
    }

    fn get_num(&self, reg: ValueID) -> f64 {
        match *self.get(reg) {
            NumberValue(v) => v,
            _ => panic!(),
        }
    }

    fn get_vec<'s>(&'s self, reg: ValueID) -> &'s [Value] {
        match *self.get(reg) {
            VectorValue(ref v) => v.as_slice(),
            _ => panic!(),
        }
    }

    fn execute(&mut self, dest: ValueID, op: &ValOp) -> bool {
        debug!("execute: {} = {}", dest, op);
        let v = match *op {
            ConstOp(ref v) => v.clone(),
            CheckOp(reg, ref v) => return self.get(reg) == v,
            RangeCheckOp(reg, min, max) => {
                let v = self.get_num(reg);
                return v >= min && v <= max;
            }

            ChooseOp(reg, ref arms) =>
                eval_choose(self.get(reg), arms.as_slice()).unwrap(),

            ElemOp(reg, index) => self.get_vec(reg)[index].clone(),

            SliceOp(reg, offset, length) =>
                VectorValue(self.get_vec(reg).slice(offset, offset+length).to_vec()),

            ConcatOp(ref parts) => {
                let mut v = Vec::new();
                for part in parts.iter() {
                    match *part {
                        ConstSlice(ref s) => v.extend(s.iter().map(|x| x.clone())),
                        DynElem(reg) => v.push(self.get(reg).clone()),
                        DynSlice(reg, len) => {
                            let s = self.get_vec(reg);
                            assert!(s.len() == len);
                            v.extend(s.iter().map(|x| x.clone()))
                        }
                    }
                }
                VectorValue(v)
            },

            BinaryOp(a, op, b) =>
                NumberValue(op.eval(self.get_num(a), self.get_num(b))),
            BinaryConstOp(a, op, b)  =>
                NumberValue(op.eval(self.get_num(a), b)),
        };
        self.set(dest, v);
        true
    }

    pub fn enter(&mut self, ops: &Ops) {
        for &(dest, ref op) in ops.entry.iter() {
            assert!(self.execute(dest, op));
        }
    }

    pub fn exit(&mut self, ops: &Ops) -> bool {
        let mut success = true;
        for &(dest, ref op) in ops.exit.iter().rev() {
                success &= self.execute(dest, op);
        }
        debug!("success: {}", success);
        success
    }
}

fn value_match(a: &Value, b: &Value) -> bool {
    a == b
}

pub fn eval_choose(v: &Value, choices: &[(Value, Value)]) -> Option<Value> {
    choices.iter().find(|& &(ref a, _)|{ value_match(a, v) }).map(|&(_, ref b)| b.clone())
}
<commit_msg>Implicit conversion from integer to number<commit_after>use std::collections::VecMap;
use ast:: {
    Value,
        NumberValue,
        IntegerValue,
        VectorValue,
};
use resolve::context::{ValueID};

#[deriving(PartialEq, Show)]
pub enum ValueSrc {
    ConstSlice(Vec<Value>),
    DynElem(ValueID),
    DynSlice(ValueID, uint),
}

#[deriving(PartialEq, Show)]
pub enum ValOp {
    ConstOp(Value),
    CheckOp(ValueID, Value),
    RangeCheckOp(ValueID, f64, f64),

    ChooseOp(ValueID, Vec<(Value, Value)>),

    SliceOp(ValueID, /*offset*/ uint, /*length*/ uint),
    ElemOp(ValueID, uint),
    ConcatOp(Vec<ValueSrc>),

    BinaryOp(ValueID, BinOp, ValueID),
    BinaryConstOp(ValueID, BinOp, f64),
}

impl ValOp {
    pub fn each_dep(&self, f: |ValueID| -> ()) {
        match *self {
            ConstOp(..) => (),
            CheckOp(i, _) => f(i),
            RangeCheckOp(i, _, _) => f(i),
            ChooseOp(i, _) => f(i),
            SliceOp(i, _, _) => f(i),
            ElemOp(i, _) => f(i),
            ConcatOp(ref l) => {
                for src in l.iter() {
                    match *src {
                        ConstSlice(..) => (),
                        DynElem(i) => f(i),
                        DynSlice(i, _) => f(i)
                    }
                }
            }
            BinaryOp(l, _, r) => { f(l); f(r) }
            BinaryConstOp(i, _, _) => f(i),
        }
    }

    pub fn all_deps(&self, f: |ValueID| -> bool) -> bool {
        let mut r = true;
        self.each_dep(|id| r &= f(id));
        r
    }
}

/// Binary numeric operators
#[deriving(PartialEq, Eq, Show)]
pub enum BinOp {
    BiAdd,       // a + b
    BiSub,       // a - b
    BiSubSwap,   // b - a

    BiMul,       // a * b
    BiDiv,       // a / b
    BiDivSwap,   // b / a
}

impl BinOp {
    /// a `op` b
    pub fn eval(&self, a: f64, b: f64) -> f64 {
        match *self {
            BiAdd     => a + b,
            BiSub     => a - b,
            BiSubSwap => b - a,
            BiMul     => a * b,
            BiDiv     => a / b,
            BiDivSwap => b / a,
        }
    }

    /// (a `op` b) == (b `op.swap()` a)
    pub fn swap(&self) -> BinOp {
        match *self {
            BiAdd     => BiAdd,
            BiSub     => BiSubSwap,
            BiSubSwap => BiSub,
            BiMul     => BiMul,
            BiDiv     => BiDivSwap,
            BiDivSwap => BiDiv,
        }
    }

    /// ((a `op` b) `op.invert()` b) == a
    pub fn invert(&self) -> BinOp {
        match *self {
            BiAdd     => BiSub,
            BiSub     => BiAdd,
            BiSubSwap => BiSubSwap,
            BiMul     => BiDiv,
            BiDiv     => BiMul,
            BiDivSwap => BiDivSwap,
        }
    }
}

#[deriving(Show)]
pub struct Ops {
    pub entry: Vec<(ValueID, ValOp)>,
    pub exit: Vec<(ValueID, ValOp)>,
}

impl Ops {
    pub fn new() -> Ops { Ops{ entry: Vec::new(), exit: Vec::new() } }
    pub fn count(&self) -> uint { self.entry.len() + self.exit.len() }
}

pub struct State {
    registers: VecMap<Value>,
}

impl State {
    pub fn new() -> State {
        let mut s = State {
            registers: VecMap::new()
        };
        // TODO: shouldn't be necessary (we currently read from 0 on ignores)
        s.registers.insert(0, ::ast::SymbolValue("invalid".to_string()));
        s
    }

    pub fn get(&self, reg: ValueID) -> &Value {
        debug!("get {}: {}", reg, self.registers.find(&reg));
        &self.registers[reg]
    }

    pub fn set(&mut self, reg: ValueID, v: Value) -> bool {
        debug!("set {}: {}", reg, v);
        // TODO: should assert the register is not already set, once exec doesn't run things twice
        self.registers.insert(reg, v);
        true
    }

    fn get_num(&self, reg: ValueID) -> f64 {
        match *self.get(reg) {
            NumberValue(v) => v,
            IntegerValue(v) => v as f64, // TODO: explicit conversion?
            _ => panic!(),
        }
    }

    fn get_vec<'s>(&'s self, reg: ValueID) -> &'s [Value] {
        match *self.get(reg) {
            VectorValue(ref v) => v.as_slice(),
            _ => panic!(),
        }
    }

    fn execute(&mut self, dest: ValueID, op: &ValOp) -> bool {
        debug!("execute: {} = {}", dest, op);
        let v = match *op {
            ConstOp(ref v) => v.clone(),
            CheckOp(reg, ref v) => return self.get(reg) == v,
            RangeCheckOp(reg, min, max) => {
                let v = self.get_num(reg);
                return v >= min && v <= max;
            }

            ChooseOp(reg, ref arms) =>
                eval_choose(self.get(reg), arms.as_slice()).unwrap(),

            ElemOp(reg, index) => self.get_vec(reg)[index].clone(),

            SliceOp(reg, offset, length) =>
                VectorValue(self.get_vec(reg).slice(offset, offset+length).to_vec()),

            ConcatOp(ref parts) => {
                let mut v = Vec::new();
                for part in parts.iter() {
                    match *part {
                        ConstSlice(ref s) => v.extend(s.iter().map(|x| x.clone())),
                        DynElem(reg) => v.push(self.get(reg).clone()),
                        DynSlice(reg, len) => {
                            let s = self.get_vec(reg);
                            assert!(s.len() == len);
                            v.extend(s.iter().map(|x| x.clone()))
                        }
                    }
                }
                VectorValue(v)
            },

            BinaryOp(a, op, b) =>
                NumberValue(op.eval(self.get_num(a), self.get_num(b))),
            BinaryConstOp(a, op, b)  =>
                NumberValue(op.eval(self.get_num(a), b)),
        };
        self.set(dest, v);
        true
    }

    pub fn enter(&mut self, ops: &Ops) {
        for &(dest, ref op) in ops.entry.iter() {
            assert!(self.execute(dest, op));
        }
    }

    pub fn exit(&mut self, ops: &Ops) -> bool {
        let mut success = true;
        for &(dest, ref op) in ops.exit.iter().rev() {
                success &= self.execute(dest, op);
        }
        debug!("success: {}", success);
        success
    }
}

fn value_match(a: &Value, b: &Value) -> bool {
    a == b
}

pub fn eval_choose(v: &Value, choices: &[(Value, Value)]) -> Option<Value> {
    choices.iter().find(|& &(ref a, _)|{ value_match(a, v) }).map(|&(_, ref b)| b.clone())
}
<|endoftext|>