<commit_before>extern crate rustbox;

use std::default::Default;

use rustbox::{Color, RustBox};
use rustbox::Key;
use rustbox::{RB_BOLD, RB_NORMAL};

use std::time::Duration;

use game;
use lila;

#[derive(Clone, Copy)]
struct RBStyle {
    style: rustbox::Style,
    fg: Color,
    bg: Color,
}

trait View {
    fn tick(&mut self);
    fn name(&self) -> &str;
    fn render(&self, ui: &mut Renderer);
    fn key_event(&mut self, key: rustbox::keyboard::Key) -> MenuResult;
}

enum MenuResult {
    AddGameView { name: String, url: String },
    None
}

struct MenuView {
    menu_options: Vec<MenuOption>,
    current: usize,
}

struct GameView {
    name: String,
    #[allow(dead_code)]
    url: String,
    povs: Vec<game::ConnectedPov>,
    input: Vec<char>,
}

pub enum MenuOption {
    WatchTv {
        name: String,
        url: String,
    },
}

pub struct UI {
    running: bool,
    renderer: Renderer,
    views: Vec<Box<View>>,
    current_view: usize,
    session: lila::Session,
}

struct Renderer {
    rb: RustBox,
}

impl UI {
    pub fn new(session: lila::Session) -> UI {

        let rb = match RustBox::init(Default::default()) {
            Result::Ok(v) => v,
            Result::Err(e) => panic!("{}", e),
        };

        let mut views = Vec::new();
        let mut menu_options = Vec::new();

        for game in &session.user.nowPlaying {
            menu_options.push(MenuOption::WatchTv { name: game.opponent.username.clone(), url: game.fullId.clone() });
        }

        menu_options.push(MenuOption::WatchTv { name: "Best".into(), url: "tv/best".into() });
        menu_options.push(MenuOption::WatchTv { name: "Bullet".into(), url: "tv/bullet".into() });
        menu_options.push(MenuOption::WatchTv { name: "Blitz".into(), url: "tv/blitz".into() });
        menu_options.push(MenuOption::WatchTv { name: "Classical".into(), url: "tv/classical".into() });
        menu_options.push(MenuOption::WatchTv { name: "Crazyhouse".into(), url: "tv/crazyhouse".into() });
        menu_options.push(MenuOption::WatchTv { name: "Chess 960".into(), url: "tv/chess960".into() });
        menu_options.push(MenuOption::WatchTv { name: "King of the Hill".into(), url: "tv/kingOfTheHill".into() });
        menu_options.push(MenuOption::WatchTv { name: "Three-Check".into(), url: "tv/threeCheck".into() });
        menu_options.push(MenuOption::WatchTv { name: "Antichess".into(), url: "tv/antichess".into() });
        menu_options.push(MenuOption::WatchTv { name: "Atomic".into(), url: "tv/atomic".into() });
        menu_options.push(MenuOption::WatchTv { name: "Horde".into(), url: "tv/horde".into() });
        menu_options.push(MenuOption::WatchTv { name: "Racing Kings".into(), url: "tv/racingKings".into() });
        menu_options.push(MenuOption::WatchTv { name: "Computer".into(), url: "tv/computer".into() });

        views.push(Box::new(MenuView {
            menu_options: menu_options,
            current: 0,
        }) as Box<View>);

        return UI {
            running: true,
            renderer: Renderer { rb: rb },
            views: views,
            current_view: 0,
            session: session,
        };
    }

    fn add_view(&mut self, view: Box<View>) {
        self.views.push(view);
    }

    fn add_game(&mut self, name: String, url: String) {
        let game = GameView::new(&self.session, name, url);
        self.add_view(Box::new(game) as Box<View>);
    }

    pub fn start(&mut self) {
        while self.running {
            self.tick();
            self.render();
            self.poll_keys();
        }
    }

    fn prev_view(&mut self) {
        if 0 < self.current_view {
            self.current_view -= 1;
            self.renderer.clear();
        }
    }

    fn next_view(&mut self) {
        if self.current_view < self.views.len() - 1 {
            self.current_view += 1;
            self.renderer.clear();
        }
    }

    fn current_view(&mut self) -> &mut Box<View> {
        self.views.get_mut(self.current_view).unwrap()
    }

    pub fn poll_keys(&mut self) {
        match self.renderer.rb.peek_event(Duration::from_millis(100), false) {
            Ok(rustbox::Event::KeyEvent(key)) => {
                match key {
                    Key::Char('q') => self.running = false,
                    Key::Left => self.prev_view(),
                    Key::Right => self.next_view(),
                    key => {
                        match self.current_view().key_event(key) {
                            MenuResult::AddGameView { name, url } => {
                                self.add_game(name, url);
                            }
                            MenuResult::None => {},
                        }
                    }
                }
            },
            Err(e) => panic!("{}", e),
            _ => { }
        }
    }

    pub fn tick(&mut self) {
        self.views.get_mut(self.current_view).unwrap().tick();
    }

    pub fn render(&mut self) {
        let dark  = RBStyle { style: RB_NORMAL, fg: Color::Blue, bg: Color::Black };
        let light = RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: Color::Black };

        self.renderer.print(0, 0, dark, "|");
        let mut x = 2;
        for (i, view) in self.views.iter().enumerate() {
            if i == self.current_view {
                self.renderer.print(x, 0, light, view.name());
            } else {
                self.renderer.print(x, 0, dark, view.name());
            }
            x += view.name().len() + 3;
            self.renderer.print(x- 2, 0, dark, "|");
        }

        self.views.get(self.current_view).unwrap().render(&mut self.renderer);
        self.renderer.present();
    }

}

impl Renderer {
    pub fn print(&self, x: usize, y: usize, rbstyle: RBStyle, chars: &str) {
        self.rb.print(x, y, rbstyle.style, rbstyle.fg, rbstyle.bg, chars);
    }

    pub fn clear(&self) {
        self.rb.clear();
    }

    pub fn present(&self) {
        self.rb.present();
    }
}

impl View for MenuView {
    fn tick(&mut self) {
    }

    fn render(&self, r: &mut Renderer) {
        let dark  = RBStyle { style: RB_BOLD, fg: Color::Blue, bg:     Color::Black };
        let light = RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: Color::Black };

        for (i, option) in self.menu_options.iter().enumerate() {
            if i == self.current {
                r.print(0, 2 + i, light, option.name());
            } else {
                r.print(0, 2 + i, dark, option.name());
            }
        }
    }

    fn name(&self) -> &str {
        "Menu"
    }

    fn key_event(&mut self, key: rustbox::keyboard::Key) -> MenuResult {
        match key {
            Key::Up => {
                if 0 < self.current {
                    self.current -= 1;
                }
                MenuResult::None
            },
            Key::Down => {
                if self.current < self.menu_options.len() -1 {
                    self.current += 1;
                }
                MenuResult::None
            },
            Key::Enter => {
                let option = self.menu_options.get(self.current).unwrap(); // TODO
                option.execute()
            }
            _ => { MenuResult::None }
        }
    }
}

impl View for GameView {
    fn tick(&mut self) {
        for pov in self.povs.iter() {
            pov.pov.lock().ok().map(|mut p| {
                p.tick();
            });
        }
    }

    fn render(&self, r: &mut Renderer) {
        for (i, pov) in self.povs.iter().enumerate() {
            pov.pov.lock().ok().map(|p| self.render_pov(r, i * 30, 0, &p));
            pov.latency.lock().ok().map(|l| self.render_latency(r, i * 30, 0, &l));
        }
        let style = RBStyle { style: RB_BOLD, fg: Color::White, bg: Color::Black };
        r.print(5, 16, style, &format!("Move {}▍          ", self.input.iter().cloned().collect::<String>()));
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn key_event(&mut self, key: Key) -> MenuResult {
        match key {
            Key::Enter => {
                self.handle_input();
            }
            Key::Char(x) => {
                self.input.push(x);
            }
            Key::Backspace => {
                self.input.pop();
            }
            _ => ()
        }
        MenuResult::None
    }
}

impl MenuView {
}

impl GameView {
    pub fn new(session: &lila::Session, name: String, url: String) -> GameView {
        let mut povs = Vec::new();

        let connected_pov = game::ConnectedPov::new(session, &url);
        povs.push(connected_pov);

        return GameView {
            name: name,
            url: url,
            povs: povs,
            input: vec!(),
        };
    }

    fn handle_input(&mut self) {
        if self.input.len() == 4 { // assume move for now
            let from: String = self.input[0..2].iter().cloned().collect();
            let to: String = self.input[2..4].iter().cloned().collect();
            self.povs.get_mut(0).unwrap().send_move(from, to);
            self.input.clear();
        }
    }

    pub fn render_latency(&self, r: &mut Renderer, x: usize, y: usize, latency: &game::LatencyRecorder) {
        let style = RBStyle { style: RB_NORMAL, fg: Color::Cyan, bg: Color::Black };
        r.print(x, y+13, style, &format!("{:3}ms", latency.average()));
    }

    pub fn render_pov(&self, r: &mut Renderer, x: usize, y: usize, pov: &game::Pov) {
        self.render_player(r, x + 1, y + 2, &pov.opponent);
        self.render_player(r, x + 1, y + 14, &pov.player);
        let fen = pov.game.fen.clone();
        self.render_fen(r, x, y, fen, pov.orientation() == game::Color::white);
        match pov.clock {
            Some(ref clock) => {
                self.render_clock(r, x + 19, y + 3, clock.from(!pov.orientation()));
                self.render_clock(r, x + 19, y + 12, clock.from(pov.orientation()));
            },
            None => ()
        };
    }

    pub fn render_player(&self, r: &mut Renderer, x: usize, y: usize, player: &game::Player) {
        let style = RBStyle { style: RB_BOLD, fg: Color::White, bg: Color::Black };
        r.print(x, y, style, &format!("{:4}", player.rating.unwrap_or(1500)));
        match player.user {
            Some(ref user) => {
                r.print(x + 5, y, style, &format!("{}", user.username));
            },
            None => ()
        };
    }

    pub fn render_clock(&self, r: &mut Renderer, x: usize, y: usize, time: f64) {
        r.print(x, y, RBStyle { style: RB_BOLD, fg: if time < 10f64 { Color::Red } else { Color::White }, bg: Color::Black }, &format!("{:04.1}", time));
    }

    pub fn render_fen(&self, r: &mut Renderer, x: usize, y: usize, fen: String, orientation: bool) {
        let _text_style  = RBStyle { style: RB_BOLD, fg: Color::White, bg:    Color::Black };
        let border      = RBStyle { style: RB_NORMAL, fg: Color::Cyan, bg:   Color::Black };
        let piece_dark  = RBStyle { style: RB_BOLD, fg: Color::Blue, bg:     Color::Black };
        let piece_light = RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: Color::Black };
        let space_dark  = RBStyle { style: RB_BOLD, fg: Color::Blue, bg:     Color::Black };
        let space_light = RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: Color::Black };

        //r.print(x + 3, y +  1, text_style, &fen);
        r.print(x + 5, y +  3, border, "╔═════════════════╗");
        r.print(x + 5, y + 12, border, "╚═════════════════╝");
        if orientation {
            r.print(x + 7, y + 13, border,   "a b c d e f g h");
        } else {
            r.print(x + 7, y + 13, border,   "h g f e d c b a");
        }

        // TODO: fen parser
        // r1bqkb1r/ppp1pppp/2n2n2/3p4/4P3/3P1P2/PPP3PP/RNBQKBNR w KQkq - 1 4
        let mut fen = fen.split(' ').next().unwrap().to_string();
        if !orientation {
            fen = fen.chars().rev().collect();
        }
        for (y2, row) in fen.split('/').enumerate() {
            if y2 >= 8 {
                break; // temp workaround for crazyhouse
            }
            let row = row
                .replace("8", "········")
                .replace("7", "·······")
                .replace("6", "······")
                .replace("5", "·····")
                .replace("4", "····")
                .replace("3", "···")
                .replace("2", "··")
                .replace("1", "·");
            if orientation {
                r.print(x + 3, 4 + y + y2, border, &format!("{} ║", 9-(y2+1)));
            } else {
                r.print(x + 3, 4 + y + y2, border, &format!("{} ║", y2+1));
            }
            r.print(x + 23, 4 + y + y2, border, "║");
            for (x2, char) in row.chars().enumerate() {
                let color = if char == '·' {
                    if (y2 + x2) % 2 == 0 {
                        space_light
                    } else {
                        space_dark
                    }
                } else {
                    if char.is_uppercase() {
                        piece_light
                    } else {
                        piece_dark
                    }
                };
                r.print(7 + x + x2*2, 4 + y + y2, color, &char.to_uppercase().collect::<String>());
            }
        }
    }
}

impl MenuOption {
    pub fn name(&self) -> &str {
        match self {
            &MenuOption::WatchTv {ref name, ..} => { // TODO remove url
               name
            },
        }
    }

    fn execute(&self) -> MenuResult {
        match self {
            &MenuOption::WatchTv {ref name, ref url} => {
                MenuResult::AddGameView { name: name.clone(), url: url.clone() }
            },
            //_ => { MenuResult::None }
        }
    }
}
<commit_msg>remove multiple povs support<commit_after>extern crate rustbox;

use std::default::Default;

use rustbox::{Color, RustBox};
use rustbox::Key;
use rustbox::{RB_BOLD, RB_NORMAL};

use std::time::Duration;

use game;
use lila;

#[derive(Clone, Copy)]
struct RBStyle {
    style: rustbox::Style,
    fg: Color,
    bg: Color,
}

trait View {
    fn tick(&mut self);
    fn name(&self) -> &str;
    fn render(&self, ui: &mut Renderer);
    fn key_event(&mut self, key: rustbox::keyboard::Key) -> MenuResult;
}

enum MenuResult {
    AddGameView { name: String, url: String },
    None
}

struct MenuView {
    menu_options: Vec<MenuOption>,
    current: usize,
}

struct GameView {
    name: String,
    #[allow(dead_code)]
    url: String,
    pov: game::ConnectedPov,
    input: Vec<char>,
}

pub enum MenuOption {
    WatchTv {
        name: String,
        url: String,
    },
}

pub struct UI {
    running: bool,
    renderer: Renderer,
    views: Vec<Box<View>>,
    current_view: usize,
    session: lila::Session,
}

struct Renderer {
    rb: RustBox,
}

impl UI {
    pub fn new(session: lila::Session) -> UI {

        let rb = match RustBox::init(Default::default()) {
            Result::Ok(v) => v,
            Result::Err(e) => panic!("{}", e),
        };

        let mut views = Vec::new();
        let mut menu_options = Vec::new();

        for game in &session.user.nowPlaying {
            menu_options.push(MenuOption::WatchTv { name: game.opponent.username.clone(), url: game.fullId.clone() });
        }

        menu_options.push(MenuOption::WatchTv { name: "Best".into(), url: "tv/best".into() });
        menu_options.push(MenuOption::WatchTv { name: "Bullet".into(), url: "tv/bullet".into() });
        menu_options.push(MenuOption::WatchTv { name: "Blitz".into(), url: "tv/blitz".into() });
        menu_options.push(MenuOption::WatchTv { name: "Classical".into(), url: "tv/classical".into() });
        menu_options.push(MenuOption::WatchTv { name: "Crazyhouse".into(), url: "tv/crazyhouse".into() });
        menu_options.push(MenuOption::WatchTv { name: "Chess 960".into(), url: "tv/chess960".into() });
        menu_options.push(MenuOption::WatchTv { name: "King of the Hill".into(), url: "tv/kingOfTheHill".into() });
        menu_options.push(MenuOption::WatchTv { name: "Three-Check".into(), url: "tv/threeCheck".into() });
        menu_options.push(MenuOption::WatchTv { name: "Antichess".into(), url: "tv/antichess".into() });
        menu_options.push(MenuOption::WatchTv { name: "Atomic".into(), url: "tv/atomic".into() });
        menu_options.push(MenuOption::WatchTv { name: "Horde".into(), url: "tv/horde".into() });
        menu_options.push(MenuOption::WatchTv { name: "Racing Kings".into(), url: "tv/racingKings".into() });
        menu_options.push(MenuOption::WatchTv { name: "Computer".into(), url: "tv/computer".into() });

        views.push(Box::new(MenuView {
            menu_options: menu_options,
            current: 0,
        }) as Box<View>);

        return UI {
            running: true,
            renderer: Renderer { rb: rb },
            views: views,
            current_view: 0,
            session: session,
        };
    }

    fn add_view(&mut self, view: Box<View>) {
        self.views.push(view);
    }

    fn add_game(&mut self, name: String, url: String) {
        let game = GameView::new(&self.session, name, url);
        self.add_view(Box::new(game) as Box<View>);
    }

    pub fn start(&mut self) {
        while self.running {
            self.tick();
            self.render();
            self.poll_keys();
        }
    }

    fn prev_view(&mut self) {
        if 0 < self.current_view {
            self.current_view -= 1;
            self.renderer.clear();
        }
    }

    fn next_view(&mut self) {
        if self.current_view < self.views.len() - 1 {
            self.current_view += 1;
            self.renderer.clear();
        }
    }

    fn current_view(&mut self) -> &mut Box<View> {
        self.views.get_mut(self.current_view).unwrap()
    }

    pub fn poll_keys(&mut self) {
        match self.renderer.rb.peek_event(Duration::from_millis(100), false) {
            Ok(rustbox::Event::KeyEvent(key)) => {
                match key {
                    Key::Char('q') => self.running = false,
                    Key::Left => self.prev_view(),
                    Key::Right => self.next_view(),
                    key => {
                        match self.current_view().key_event(key) {
                            MenuResult::AddGameView { name, url } => {
                                self.add_game(name, url);
                            }
                            MenuResult::None => {},
                        }
                    }
                }
            },
            Err(e) => panic!("{}", e),
            _ => { }
        }
    }

    pub fn tick(&mut self) {
        self.views.get_mut(self.current_view).unwrap().tick();
    }

    pub fn render(&mut self) {
        let dark  = RBStyle { style: RB_NORMAL, fg: Color::Blue, bg: Color::Black };
        let light = RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: Color::Black };

        self.renderer.print(0, 0, dark, "|");
        let mut x = 2;
        for (i, view) in self.views.iter().enumerate() {
            if i == self.current_view {
                self.renderer.print(x, 0, light, view.name());
            } else {
                self.renderer.print(x, 0, dark, view.name());
            }
            x += view.name().len() + 3;
            self.renderer.print(x- 2, 0, dark, "|");
        }

        self.views.get(self.current_view).unwrap().render(&mut self.renderer);
        self.renderer.present();
    }

}

impl Renderer {
    pub fn print(&self, x: usize, y: usize, rbstyle: RBStyle, chars: &str) {
        self.rb.print(x, y, rbstyle.style, rbstyle.fg, rbstyle.bg, chars);
    }

    pub fn clear(&self) {
        self.rb.clear();
    }

    pub fn present(&self) {
        self.rb.present();
    }
}

impl View for MenuView {
    fn tick(&mut self) {
    }

    fn render(&self, r: &mut Renderer) {
        let dark  = RBStyle { style: RB_BOLD, fg: Color::Blue, bg:     Color::Black };
        let light = RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: Color::Black };

        for (i, option) in self.menu_options.iter().enumerate() {
            if i == self.current {
                r.print(0, 2 + i, light, option.name());
            } else {
                r.print(0, 2 + i, dark, option.name());
            }
        }
    }

    fn name(&self) -> &str {
        "Menu"
    }

    fn key_event(&mut self, key: rustbox::keyboard::Key) -> MenuResult {
        match key {
            Key::Up => {
                if 0 < self.current {
                    self.current -= 1;
                }
                MenuResult::None
            },
            Key::Down => {
                if self.current < self.menu_options.len() -1 {
                    self.current += 1;
                }
                MenuResult::None
            },
            Key::Enter => {
                let option = self.menu_options.get(self.current).unwrap(); // TODO
                option.execute()
            }
            _ => { MenuResult::None }
        }
    }
}

impl View for GameView {
    fn tick(&mut self) {
        self.pov.pov.lock().ok().map(|mut p| {
            p.tick();
        });
    }

    fn render(&self, r: &mut Renderer) {
        self.pov.pov.lock().ok().map(|p| self.render_pov(r, 0, 0, &p));
        self.pov.latency.lock().ok().map(|l| self.render_latency(r, 0, 0, &l));
        let style = RBStyle { style: RB_BOLD, fg: Color::White, bg: Color::Black };
        r.print(5, 16, style, &format!("Move {}▍          ", self.input.iter().cloned().collect::<String>()));
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn key_event(&mut self, key: Key) -> MenuResult {
        match key {
            Key::Enter => {
                self.handle_input();
            }
            Key::Char(x) => {
                self.input.push(x);
            }
            Key::Backspace => {
                self.input.pop();
            }
            _ => ()
        }
        MenuResult::None
    }
}

impl MenuView {
}

impl GameView {
    pub fn new(session: &lila::Session, name: String, url: String) -> GameView {
        let connected_pov = game::ConnectedPov::new(session, &url);

        return GameView {
            name: name,
            url: url,
            pov: connected_pov,
            input: vec!(),
        };
    }

    fn handle_input(&mut self) {
        if self.input.len() == 4 { // assume move for now
            let from: String = self.input[0..2].iter().cloned().collect();
            let to: String = self.input[2..4].iter().cloned().collect();
            self.pov.send_move(from, to);
            self.input.clear();
        }
    }

    pub fn render_latency(&self, r: &mut Renderer, x: usize, y: usize, latency: &game::LatencyRecorder) {
        let style = RBStyle { style: RB_NORMAL, fg: Color::Cyan, bg: Color::Black };
        r.print(x, y+13, style, &format!("{:3}ms", latency.average()));
    }

    pub fn render_pov(&self, r: &mut Renderer, x: usize, y: usize, pov: &game::Pov) {
        self.render_player(r, x + 1, y + 2, &pov.opponent);
        self.render_player(r, x + 1, y + 14, &pov.player);
        let fen = pov.game.fen.clone();
        self.render_fen(r, x, y, fen, pov.orientation() == game::Color::white);
        match pov.clock {
            Some(ref clock) => {
                self.render_clock(r, x + 19, y + 3, clock.from(!pov.orientation()));
                self.render_clock(r, x + 19, y + 12, clock.from(pov.orientation()));
            },
            None => ()
        };
    }

    pub fn render_player(&self, r: &mut Renderer, x: usize, y: usize, player: &game::Player) {
        let style = RBStyle { style: RB_BOLD, fg: Color::White, bg: Color::Black };
        r.print(x, y, style, &format!("{:4}", player.rating.unwrap_or(1500)));
        match player.user {
            Some(ref user) => {
                r.print(x + 5, y, style, &format!("{}", user.username));
            },
            None => ()
        };
    }

    pub fn render_clock(&self, r: &mut Renderer, x: usize, y: usize, time: f64) {
        r.print(x, y, RBStyle { style: RB_BOLD, fg: if time < 10f64 { Color::Red } else { Color::White }, bg: Color::Black }, &format!("{:04.1}", time));
    }

    pub fn render_fen(&self, r: &mut Renderer, x: usize, y: usize, fen: String, orientation: bool) {
        let _text_style  = RBStyle { style: RB_BOLD, fg: Color::White, bg:    Color::Black };
        let border      = RBStyle { style: RB_NORMAL, fg: Color::Cyan, bg:   Color::Black };
        let piece_dark  = RBStyle { style: RB_BOLD, fg: Color::Blue, bg:     Color::Black };
        let piece_light = RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: Color::Black };
        let space_dark  = RBStyle { style: RB_BOLD, fg: Color::Blue, bg:     Color::Black };
        let space_light = RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: Color::Black };

        //r.print(x + 3, y +  1, text_style, &fen);
        r.print(x + 5, y +  3, border, "╔═════════════════╗");
        r.print(x + 5, y + 12, border, "╚═════════════════╝");
        if orientation {
            r.print(x + 7, y + 13, border,   "a b c d e f g h");
        } else {
            r.print(x + 7, y + 13, border,   "h g f e d c b a");
        }

        // TODO: fen parser
        // r1bqkb1r/ppp1pppp/2n2n2/3p4/4P3/3P1P2/PPP3PP/RNBQKBNR w KQkq - 1 4
        let mut fen = fen.split(' ').next().unwrap().to_string();
        if !orientation {
            fen = fen.chars().rev().collect();
        }
        for (y2, row) in fen.split('/').enumerate() {
            if y2 >= 8 {
                break; // temp workaround for crazyhouse
            }
            let row = row
                .replace("8", "········")
                .replace("7", "·······")
                .replace("6", "······")
                .replace("5", "·····")
                .replace("4", "····")
                .replace("3", "···")
                .replace("2", "··")
                .replace("1", "·");
            if orientation {
                r.print(x + 3, 4 + y + y2, border, &format!("{} ║", 9-(y2+1)));
            } else {
                r.print(x + 3, 4 + y + y2, border, &format!("{} ║", y2+1));
            }
            r.print(x + 23, 4 + y + y2, border, "║");
            for (x2, char) in row.chars().enumerate() {
                let color = if char == '·' {
                    if (y2 + x2) % 2 == 0 {
                        space_light
                    } else {
                        space_dark
                    }
                } else {
                    if char.is_uppercase() {
                        piece_light
                    } else {
                        piece_dark
                    }
                };
                r.print(7 + x + x2*2, 4 + y + y2, color, &char.to_uppercase().collect::<String>());
            }
        }
    }
}

impl MenuOption {
    pub fn name(&self) -> &str {
        match self {
            &MenuOption::WatchTv {ref name, ..} => { // TODO remove url
               name
            },
        }
    }

    fn execute(&self) -> MenuResult {
        match self {
            &MenuOption::WatchTv {ref name, ref url} => {
                MenuResult::AddGameView { name: name.clone(), url: url.clone() }
            },
            //_ => { MenuResult::None }
        }
    }
}
<|endoftext|>


<commit_before>//! Types representing for data which will be retrieved from the database.
//! Currently this data is expected to look like a JSON object but this may be
//! changed in the future. Driver authors must cast the data they retrieve from
//! the database to these types.

use std::collections::BTreeMap;
use structure::Collection;

/// Represents a JSON pointer to a document property.
pub type Pointer = Vec<String>;

/// Various value types. Based on types in the [JSON standard][1] (see section
/// 5).
///
/// [1]: http://ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
pub enum Value {
  /// The abscense of any value.
  Null,
  /// True or false.
  Boolean(bool),
  /// A numeric value, float, integer, whatever.
  Number(f64),
  /// A list of characters.
  String(String),
  /// A list of values.
  Array(Vec<Value>),
  /// A map of key/value pairs.
  Object(BTreeMap<String, Value>),
  /// A reference to a document in another collection.
  Reference(Collection, Box<Value>)
}

/// Different database collection property updates.
pub enum Patch {
  /// Set a property to a new value.
  Set(Pointer, Value),
  /// Reset a property to its default value.
  Reset(Pointer),
  /// Remove a property from the database entirely.
  Remove(Pointer)
}

/// A recursive filter condition for a `Value`.
pub enum Filter {
  /// Combine multiple filters with an “and” operator.
  And(Vec<Box<Filter>>),
  /// Combine multiple filters with an “or” operator.
  Or(Vec<Box<Filter>>),
  /// Inverts the filter.
  Not(Box<Filter>),
  /// The basic condition of a filter.
  Condition(Pointer, FilterCondition)
}

pub enum FilterCondition {
  Equal(Value),
  OneOf(Vec<Value>),
  GreaterThan(Value),
  LessThan(Value)
}

/// A single way in which to order a collection of documents.
pub struct Ordering(Pointer, OrderDirection);

pub enum OrderDirection {
  Ascending,
  Descending
}
<commit_msg>'optimize' the values<commit_after>//! Types representing for data which will be retrieved from the database.
//! Currently this data is expected to look like a JSON object but this may be
//! changed in the future. Driver authors must cast the data they retrieve from
//! the database to these types.

use std::collections::BTreeMap;
use structure::Collection;

/// Represents a JSON pointer to a document property.
pub type Pointer = Vec<String>;

/// Various value types. Based on types in the [JSON standard][1] (see section
/// 5).
///
/// [1]: http://ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
pub enum Value {
  /// The abscense of any value.
  Null,
  /// True or false.
  Boolean(bool),
  /// A numeric value, float, integer, whatever.
  Number(f64),
  /// A list of characters.
  String(String),
  /// A list of values.
  Array(Vec<Value>),
  /// A map of key/value pairs.
  Object(Vec<(String, Value)>),
  /// A reference to a document in another collection.
  Reference(Collection, Box<Value>)
}

/// Different database collection property updates.
pub enum Patch {
  /// Set a property to a new value.
  Set(Pointer, Value),
  /// Reset a property to its default value.
  Reset(Pointer),
  /// Remove a property from the database entirely.
  Remove(Pointer)
}

/// A recursive filter condition for a `Value`.
pub enum Filter {
  /// Combine multiple filters with an “and” operator.
  And(Vec<Filter>),
  /// Combine multiple filters with an “or” operator.
  Or(Vec<Filter>),
  /// Inverts the filter.
  Not(Box<Filter>),
  /// The basic condition of a filter.
  Condition(Pointer, FilterCondition)
}

pub enum FilterCondition {
  Equal(Value),
  OneOf(Vec<Value>),
  GreaterThan(Value),
  LessThan(Value)
}

/// A single way in which to order a collection of documents.
pub struct Ordering(Pointer, OrderDirection);

pub enum OrderDirection {
  Ascending,
  Descending
}
<|endoftext|>


<commit_before>//!
//! Values manipulated by endpoints
//!

use std::time::Duration;

extern crate chrono;
use self::chrono::{DateTime, Local};

extern crate serde_json;

///
/// The type of values manipulated by endpoints.
///
#[derive(Debug, Clone)]
pub enum Type {
    ///
    /// # Trivial values
    ///

    /// An empty value. Used for instance to inform that a countdown
    /// has reached 0 or that a device is ready.
    Unit,

    /// A boolean. Used for instance for on-off switches, presence
    /// detectors, etc.
    Bool,

    ///
    /// # Time
    ///

    /// A duration. Used for instance in countdowns.
    Duration,

    /// A precise timestamp. Used for instance to determine when an
    /// event has taken place.
    TimeStamp,

    Temperature,

    ///
    /// ...
    ///
    Color,
    Json,
    Binary,
}

/// A temperature. Internal representation may be either Fahrenheit or
/// Celcius. The FoxBox adapters are expected to perform conversions
/// to the format requested by their devices.
#[derive(Debug, Clone)]
pub enum Temperature {
    /// Fahrenheit
    F(f64),
    /// Celcius
    C(f64),
}

impl Temperature {
    /// Get a temperature in Fahrenheit.
    pub fn as_f(&self) -> f64 {
        unimplemented!();
    }

    /// Get a temperature in Celcius.
    pub fn as_c(&self) -> f64 {
        unimplemented!();
    }
}

/// A color. Internal representation may vary. The FoxBox adapters are
/// expected to perform conversions to the format requested by their
/// device.
#[derive(Debug, Clone)]
pub enum Color {
    RGBA(f64, f64, f64, f64, f64)
}

/// An actual value that may be transmitted from/to a Service.
#[derive(Debug, Clone)]
pub enum Value {
    Unit,
    Bool(bool),
    Duration(Duration),
    TimeStamp(chrono::DateTime<Local>),
    Temperature(Temperature),
    Color(Color),

    // FIXME: Add more as we identify needs
    Json(serde_json::value::Value),
    Binary {data: Vec<u8>, mimetype: String}
}

impl Value {
    pub fn get_type(&self) -> Type {
        match *self {
            Value::Unit => Type::Unit,
            Value::Bool(_) => Type::Bool,
            Value::Duration(_) => Type::Duration,
            Value::TimeStamp(_) => Type::TimeStamp,
            Value::Temperature(_) => Type::Temperature,
            Value::Color(_) => Type::Color,
            Value::Json(_) => Type::Json,
            Value::Binary{..} => Type::Binary,
        }
    }
}
<commit_msg>Implementing ordering on values<commit_after>//!
//! Values manipulated by endpoints
//!

use std::time::Duration;
use std::cmp::{PartialOrd, Ordering};

extern crate chrono;
use self::chrono::{DateTime, Local};

extern crate serde_json;

///
/// The type of values manipulated by endpoints.
///
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub enum Type {
    ///
    /// # Trivial values
    ///

    /// An empty value. Used for instance to inform that a countdown
    /// has reached 0 or that a device is ready.
    Unit,

    /// A boolean. Used for instance for on-off switches, presence
    /// detectors, etc.
    Bool,

    ///
    /// # Time
    ///

    /// A duration. Used for instance in countdowns.
    Duration,

    /// A precise timestamp. Used for instance to determine when an
    /// event has taken place.
    TimeStamp,

    Temperature,

    ///
    /// ...
    ///
    Color,
    Json,
    Binary,
}

/// A temperature. Internal representation may be either Fahrenheit or
/// Celcius. The FoxBox adapters are expected to perform conversions
/// to the format requested by their devices.
#[derive(Debug, Clone, PartialEq)]
pub enum Temperature {
    /// Fahrenheit
    F(f64),
    /// Celcius
    C(f64),
}

impl Temperature {
    /// Get a temperature in Fahrenheit.
    pub fn as_f(&self) -> f64 {
        unimplemented!();
    }

    /// Get a temperature in Celcius.
    pub fn as_c(&self) -> f64 {
        unimplemented!();
    }
}

impl PartialOrd for Temperature {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.as_c().partial_cmp(&other.as_c())
    }
}

/// A color. Internal representation may vary. The FoxBox adapters are
/// expected to perform conversions to the format requested by their
/// device.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Color {
    RGBA(f64, f64, f64, f64, f64)
}

/// Representation of an object in JSON. It is often (albeit not
/// always) possible to choose a more precise data structure for
/// representing values send/accepted by a service. If possible,
/// adapters should rather pick such more precise data structure.
#[derive(Debug, Clone, PartialEq)]
pub struct Json(serde_json::value::Value);

impl PartialOrd for Json {
    /// Two Json objects are never comparable to each other.
    fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
        None
    }
}

/// Base definitions for actual values. Most API clients will rather
/// use `Value`.
///
/// Splitting the defintion between `Value` and `ValueBase` is mostly
/// a convenience to refine the automatically-derived `PartialOrd` on
/// `ValueBase` into something that will never compare two values with
/// different types.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum ValueBase {
    Unit,
    Bool(bool),
    Duration(Duration),
    TimeStamp(chrono::DateTime<Local>),
    Temperature(Temperature),
    Color(Color),

    // FIXME: Add more as we identify needs
    Json(Json),
    Binary {data: Vec<u8>, mimetype: String}
}

impl ValueBase {
    pub fn get_type(&self) -> Type {
        match *self {
            ValueBase::Unit => Type::Unit,
            ValueBase::Bool(_) => Type::Bool,
            ValueBase::Duration(_) => Type::Duration,
            ValueBase::TimeStamp(_) => Type::TimeStamp,
            ValueBase::Temperature(_) => Type::Temperature,
            ValueBase::Color(_) => Type::Color,
            ValueBase::Json(_) => Type::Json,
            ValueBase::Binary{..} => Type::Binary,
        }
    }
}

/// Representation of an actual value that can be sent to/received
/// from a service.
#[derive(Debug, Clone, PartialEq)]
pub struct Value(ValueBase);

impl Value {
    /// Get the type attached to a value.
    pub fn get_type(&self) -> Type {
        self.0.get_type()
    }
}

impl PartialOrd for Value {
    /// Two values of the same type can be compared using the usual
    /// comparison for values of this type. Two values of distinct
    /// types cannot be compared.
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        if self.get_type() != other.get_type() {
            None
        } else {
            self.0.partial_cmp(&other.0)
        }
    }
}
<|endoftext|>


<commit_before>extern crate orbfont;

use orbclient::{self, Renderer, WindowFlag};
use orbclient::color::Color;
use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::sync::Arc;

use super::{Event, FocusManager, KeyEvent, Point, Rect, Widget};
use theme::Theme;
use traits::Resize;

pub use orbclient::Window as InnerWindow;

pub struct WindowRenderer<'a> {
    inner: &'a mut InnerWindow,
    font: &'a Option<orbfont::Font>,
}

impl<'a> WindowRenderer<'a> {
    pub fn new(inner: &'a mut InnerWindow, font: &'a Option<orbfont::Font>) -> WindowRenderer<'a> {
        WindowRenderer {
            inner: inner,
            font: font,
        }
    }
}

impl<'a> Renderer for WindowRenderer<'a> {
    fn width(&self) -> u32 {
        self.inner.width()
    }

    fn height(&self) -> u32 {
        self.inner.height()
    }

    fn data(&self) -> &[Color] {
        self.inner.data()
    }

    fn data_mut(&mut self) -> &mut [Color] {
        self.inner.data_mut()
    }

    fn sync(&mut self) -> bool {
        self.inner.sync()
    }

    fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
        if let Some(ref font) = *self.font {
            let mut buf = [0; 4];
            font.render(&c.encode_utf8(&mut buf), 16.0)
                .draw(self.inner, x, y, color)
        } else {
            self.inner.char(x, y, c, color);
        }
    }
}

impl<'a> Drop for WindowRenderer<'a> {
    fn drop(&mut self) {
        self.inner.sync();
    }
}

pub struct Window {
    inner: RefCell<InnerWindow>,
    font: Option<orbfont::Font>,
    pub widgets: RefCell<Vec<Arc<Widget>>>,
    pub running: Cell<bool>,
    pub theme: Theme,
    resize_callback: RefCell<Option<Arc<Fn(&Window, u32, u32)>>>,
    mouse_point: Point,
    mouse_left: bool,
    mouse_middle: bool,
    mouse_right: bool,
    events: VecDeque<Event>,
    redraw: bool,
    focus_manager: FocusManager,
}

impl Resize for Window {
    fn emit_resize(&self, width: u32, height: u32) {
        if let Some(ref resize_callback) = *self.resize_callback.borrow() {
            resize_callback(self, width, height);
        }
    }

    fn on_resize<T: Fn(&Self, u32, u32) + 'static>(&self, func: T) -> &Self {
        *self.resize_callback.borrow_mut() = Some(Arc::new(func));
        self
    }
}

impl Window {
    pub fn new(rect: Rect, title: &str) -> Self {
        Window::new_flags(rect, title, &[])
    }

    pub fn new_flags(rect: Rect, title: &str, flags: &[WindowFlag]) -> Self {
        Window::from_inner(
            InnerWindow::new_flags(rect.x, rect.y, rect.width, rect.height, title, flags).unwrap(),
        )
    }

    pub fn from_inner(inner: InnerWindow) -> Self {
        let mut events = VecDeque::new();
        events.push_back(Event::Init);
        Window {
            inner: RefCell::new(inner),
            font: orbfont::Font::find(None, None, None).ok(),
            widgets: RefCell::new(Vec::new()),
            running: Cell::new(true),
            theme: Theme::new(),
            resize_callback: RefCell::new(None),
            mouse_point: Point::new(0, 0),
            mouse_left: false,
            mouse_right: false,
            mouse_middle: false,
            events: events,
            redraw: true,
            focus_manager: FocusManager::new(),
        }
    }

    pub fn into_inner(self) -> InnerWindow {
        self.inner.into_inner()
    }

    pub fn x(&self) -> i32 {
        let inner = self.inner.borrow();
        (*inner).x()
    }

    pub fn y(&self) -> i32 {
        let inner = self.inner.borrow();
        (*inner).y()
    }

    pub fn width(&self) -> u32 {
        let inner = self.inner.borrow();
        (*inner).width()
    }

    pub fn height(&self) -> u32 {
        let inner = self.inner.borrow();
        (*inner).height()
    }

    pub fn title(&self) -> String {
        let inner = self.inner.borrow();
        (*inner).title()
    }

    pub fn set_pos(&self, x: i32, y: i32) {
        let mut inner = self.inner.borrow_mut();
        (*inner).set_pos(x, y);
    }

    pub fn set_size(&self, width: u32, height: u32) {
        let mut inner = self.inner.borrow_mut();
        (*inner).set_size(width, height);
    }

    pub fn set_title(&self, title: &str) {
        let mut inner = self.inner.borrow_mut();
        (*inner).set_title(title);
    }

    pub fn close(&self) {
        self.running.set(false);
    }

    pub fn add<T: Widget>(&self, widget: &Arc<T>) -> usize {
        let mut widgets = self.widgets.borrow_mut();
        let id = widgets.len();
        widgets.push(widget.clone());

        if id == 0 {
            self.focus_manager.request_focus(&widgets[id]);
        }

        id
    }

    pub fn draw(&self) {
        let mut inner = self.inner.borrow_mut();
        inner.set(self.theme.color("background", &"window".into()));

        let mut renderer = WindowRenderer::new(&mut *inner, &self.font);
        for widget in self.widgets.borrow().iter() {
            self.draw_widget(&mut renderer, self.focus_manager.focused(&widget), widget);
        }
    }

    fn draw_widget(&self, renderer: &mut Renderer, focused: bool, widget: &Arc<Widget>) {
        widget.update();
        widget.draw(renderer, focused, &self.theme);

        for child in widget.children().borrow().iter() {
            self.draw_widget(renderer, self.focus_manager.focused(&child), child);
        }
    }

    pub fn set_theme(&mut self, theme: Theme) {
        self.theme = theme;
    }

    pub fn step(&mut self) {
        self.drain_orbital_events();
        self.drain_events();
    }

    pub fn drain_events(&mut self) {
        while let Some(event) = self.events.pop_front() {
            match event {
                Event::Resize { width, height } => {
                    self.emit_resize(width, height);
                }
                _ => (),
            }

            for widget in self.widgets.borrow().iter() {
                self.redraw = self.drain_event(event, self.redraw, widget);
            }
        }
    }

    fn drain_event(&self, event: Event, redraw: bool, widget: &Arc<Widget>) -> bool {
        let mut redraw = redraw;
        //let mut children_redraw = false;

        if widget.event(event, self.focus_manager.focused(&widget), &mut redraw) {
            if !self.focus_manager.focused(&widget) {
                self.focus_manager.request_focus(&widget);
                redraw = true;
            }
        }

        redraw

        // for child in &*widget.children().borrow_mut() {
        //     children_redraw = self.drain_event(event, redraw, child);
        // }

        // redraw || children_redraw
    }

    pub fn drain_orbital_events(&mut self) {
        for orbital_event in self.inner.borrow_mut().events() {
            match orbital_event.to_option() {
                orbclient::EventOption::Mouse(mouse_event) => {
                    self.mouse_point.x = mouse_event.x;
                    self.mouse_point.y = mouse_event.y;

                    self.events.push_back(Event::Mouse {
                        point: self.mouse_point,
                        left_button: self.mouse_left,
                        middle_button: self.mouse_middle,
                        right_button: self.mouse_right,
                    })
                }
                orbclient::EventOption::Button(button_event) => {
                    self.mouse_left = button_event.left;
                    self.mouse_middle = button_event.middle;
                    self.mouse_right = button_event.right;

                    self.events.push_back(Event::Mouse {
                        point: self.mouse_point,
                        left_button: self.mouse_left,
                        middle_button: self.mouse_middle,
                        right_button: self.mouse_right,
                    })
                }
                orbclient::EventOption::Scroll(scroll_event) => {
                    self.events.push_back(Event::Scroll {
                        x: scroll_event.x,
                        y: scroll_event.y,
                    })
                }
                orbclient::EventOption::Key(key_event) => if key_event.pressed {
                    self.events.push_back(Event::KeyPressed(
                        KeyEvent::from_orbital_key_event(key_event),
                    ));
                } else {
                    self.events.push_back(Event::KeyReleased(
                        KeyEvent::from_orbital_key_event(key_event),
                    ));
                },
                orbclient::EventOption::Resize(resize_event) => {
                    self.redraw = true;
                    self.events.push_back(Event::Resize {
                        width: resize_event.width,
                        height: resize_event.height,
                    });
                }
                orbclient::EventOption::Quit(_quit_event) => {
                    self.running.set(false);
                }
                _ => (),
            };
        }
    }

    pub fn exec(&mut self) {
        'event: while self.running.get() {
            self.drain_events();
            self.draw_if_needed();
            self.drain_orbital_events();
        }
    }

    pub fn needs_redraw(&mut self) {
        self.redraw = true;
    }

    pub fn draw_if_needed(&mut self) {
        if self.redraw {
            self.draw();
            self.redraw = false;
        }
    }
}

pub struct WindowBuilder<'a> {
    rect: Rect,
    title: &'a str,
    font: Option<orbfont::Font>,
    theme: Option<Theme>,
    flags: Option<&'a [WindowFlag]>,
}

impl<'a> WindowBuilder<'a> {
    pub fn new(rect: Rect, title: &'a str) -> Self {
        WindowBuilder {
            rect: rect,
            title: title,
            font: orbfont::Font::find(None, None, None).ok(),
            theme: None,
            flags: None,
        }
    }

    pub fn font(mut self, font: orbfont::Font) -> Self {
        self.font = Some(font);
        self
    }

    pub fn theme(mut self, theme: Theme) -> Self {
        self.theme = Some(theme);
        self
    }

    pub fn flags(mut self, flags: &'a [WindowFlag]) -> Self {
        self.flags = Some(flags);
        self
    }

    pub fn build(self) -> Window {
        let (rect, title, font) = (self.rect, self.title, self.font);

        let flags = match self.flags {
            Some(flags) => flags,
            None => &[],
        };

        let inner =
            InnerWindow::new_flags(rect.x, rect.y, rect.width, rect.height, title, flags).unwrap();

        let theme = match self.theme {
            Some(theme) => theme,
            None => Theme::new(),
        };

        let mut events = VecDeque::new();
        events.push_back(Event::Init);

        Window {
            inner: RefCell::new(inner),
            font: font,
            widgets: RefCell::new(Vec::new()),
            running: Cell::new(true),
            theme: theme,
            resize_callback: RefCell::new(None),
            mouse_point: Point::new(0, 0),
            mouse_left: false,
            mouse_right: false,
            mouse_middle: false,
            events: events,
            redraw: true,
            focus_manager: FocusManager::new(),
        }
    }
}
<commit_msg>Implement mode() required by trait Renderer<commit_after>extern crate orbfont;

use orbclient::{self, Renderer, Mode, WindowFlag};
use orbclient::color::Color;
use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::sync::Arc;

use super::{Event, FocusManager, KeyEvent, Point, Rect, Widget};
use theme::Theme;
use traits::Resize;

pub use orbclient::Window as InnerWindow;

pub struct WindowRenderer<'a> {
    inner: &'a mut InnerWindow,
    font: &'a Option<orbfont::Font>,
}

impl<'a> WindowRenderer<'a> {
    pub fn new(inner: &'a mut InnerWindow, font: &'a Option<orbfont::Font>) -> WindowRenderer<'a> {
        WindowRenderer {
            inner: inner,
            font: font,
        }
    }
}

impl<'a> Renderer for WindowRenderer<'a> {
    fn width(&self) -> u32 {
        self.inner.width()
    }

    fn height(&self) -> u32 {
        self.inner.height()
    }

    fn data(&self) -> &[Color] {
        self.inner.data()
    }

    fn data_mut(&mut self) -> &mut [Color] {
        self.inner.data_mut()
    }

    fn sync(&mut self) -> bool {
        self.inner.sync()
    }

    fn mode(&self) -> &Cell<Mode> {
        &self.inner.mode()
    }

    fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
        if let Some(ref font) = *self.font {
            let mut buf = [0; 4];
            font.render(&c.encode_utf8(&mut buf), 16.0)
                .draw(self.inner, x, y, color)
        } else {
            self.inner.char(x, y, c, color);
        }
    }
}

impl<'a> Drop for WindowRenderer<'a> {
    fn drop(&mut self) {
        self.inner.sync();
    }
}

pub struct Window {
    inner: RefCell<InnerWindow>,
    font: Option<orbfont::Font>,
    pub widgets: RefCell<Vec<Arc<Widget>>>,
    pub running: Cell<bool>,
    pub theme: Theme,
    resize_callback: RefCell<Option<Arc<Fn(&Window, u32, u32)>>>,
    mouse_point: Point,
    mouse_left: bool,
    mouse_middle: bool,
    mouse_right: bool,
    events: VecDeque<Event>,
    redraw: bool,
    focus_manager: FocusManager,
}

impl Resize for Window {
    fn emit_resize(&self, width: u32, height: u32) {
        if let Some(ref resize_callback) = *self.resize_callback.borrow() {
            resize_callback(self, width, height);
        }
    }

    fn on_resize<T: Fn(&Self, u32, u32) + 'static>(&self, func: T) -> &Self {
        *self.resize_callback.borrow_mut() = Some(Arc::new(func));
        self
    }
}

impl Window {
    pub fn new(rect: Rect, title: &str) -> Self {
        Window::new_flags(rect, title, &[])
    }

    pub fn new_flags(rect: Rect, title: &str, flags: &[WindowFlag]) -> Self {
        Window::from_inner(
            InnerWindow::new_flags(rect.x, rect.y, rect.width, rect.height, title, flags).unwrap(),
        )
    }

    pub fn from_inner(inner: InnerWindow) -> Self {
        let mut events = VecDeque::new();
        events.push_back(Event::Init);
        Window {
            inner: RefCell::new(inner),
            font: orbfont::Font::find(None, None, None).ok(),
            widgets: RefCell::new(Vec::new()),
            running: Cell::new(true),
            theme: Theme::new(),
            resize_callback: RefCell::new(None),
            mouse_point: Point::new(0, 0),
            mouse_left: false,
            mouse_right: false,
            mouse_middle: false,
            events: events,
            redraw: true,
            focus_manager: FocusManager::new(),
        }
    }

    pub fn into_inner(self) -> InnerWindow {
        self.inner.into_inner()
    }

    pub fn x(&self) -> i32 {
        let inner = self.inner.borrow();
        (*inner).x()
    }

    pub fn y(&self) -> i32 {
        let inner = self.inner.borrow();
        (*inner).y()
    }

    pub fn width(&self) -> u32 {
        let inner = self.inner.borrow();
        (*inner).width()
    }

    pub fn height(&self) -> u32 {
        let inner = self.inner.borrow();
        (*inner).height()
    }

    pub fn title(&self) -> String {
        let inner = self.inner.borrow();
        (*inner).title()
    }

    pub fn set_pos(&self, x: i32, y: i32) {
        let mut inner = self.inner.borrow_mut();
        (*inner).set_pos(x, y);
    }

    pub fn set_size(&self, width: u32, height: u32) {
        let mut inner = self.inner.borrow_mut();
        (*inner).set_size(width, height);
    }

    pub fn set_title(&self, title: &str) {
        let mut inner = self.inner.borrow_mut();
        (*inner).set_title(title);
    }

    pub fn close(&self) {
        self.running.set(false);
    }

    pub fn add<T: Widget>(&self, widget: &Arc<T>) -> usize {
        let mut widgets = self.widgets.borrow_mut();
        let id = widgets.len();
        widgets.push(widget.clone());

        if id == 0 {
            self.focus_manager.request_focus(&widgets[id]);
        }

        id
    }

    pub fn draw(&self) {
        let mut inner = self.inner.borrow_mut();
        inner.set(self.theme.color("background", &"window".into()));

        let mut renderer = WindowRenderer::new(&mut *inner, &self.font);
        for widget in self.widgets.borrow().iter() {
            self.draw_widget(&mut renderer, self.focus_manager.focused(&widget), widget);
        }
    }

    fn draw_widget(&self, renderer: &mut Renderer, focused: bool, widget: &Arc<Widget>) {
        widget.update();
        widget.draw(renderer, focused, &self.theme);

        for child in widget.children().borrow().iter() {
            self.draw_widget(renderer, self.focus_manager.focused(&child), child);
        }
    }

    pub fn set_theme(&mut self, theme: Theme) {
        self.theme = theme;
    }

    pub fn step(&mut self) {
        self.drain_orbital_events();
        self.drain_events();
    }

    pub fn drain_events(&mut self) {
        while let Some(event) = self.events.pop_front() {
            match event {
                Event::Resize { width, height } => {
                    self.emit_resize(width, height);
                }
                _ => (),
            }

            for widget in self.widgets.borrow().iter() {
                self.redraw = self.drain_event(event, self.redraw, widget);
            }
        }
    }

    fn drain_event(&self, event: Event, redraw: bool, widget: &Arc<Widget>) -> bool {
        let mut redraw = redraw;
        //let mut children_redraw = false;

        if widget.event(event, self.focus_manager.focused(&widget), &mut redraw) {
            if !self.focus_manager.focused(&widget) {
                self.focus_manager.request_focus(&widget);
                redraw = true;
            }
        }

        redraw

        // for child in &*widget.children().borrow_mut() {
        //     children_redraw = self.drain_event(event, redraw, child);
        // }

        // redraw || children_redraw
    }

    pub fn drain_orbital_events(&mut self) {
        for orbital_event in self.inner.borrow_mut().events() {
            match orbital_event.to_option() {
                orbclient::EventOption::Mouse(mouse_event) => {
                    self.mouse_point.x = mouse_event.x;
                    self.mouse_point.y = mouse_event.y;

                    self.events.push_back(Event::Mouse {
                        point: self.mouse_point,
                        left_button: self.mouse_left,
                        middle_button: self.mouse_middle,
                        right_button: self.mouse_right,
                    })
                }
                orbclient::EventOption::Button(button_event) => {
                    self.mouse_left = button_event.left;
                    self.mouse_middle = button_event.middle;
                    self.mouse_right = button_event.right;

                    self.events.push_back(Event::Mouse {
                        point: self.mouse_point,
                        left_button: self.mouse_left,
                        middle_button: self.mouse_middle,
                        right_button: self.mouse_right,
                    })
                }
                orbclient::EventOption::Scroll(scroll_event) => {
                    self.events.push_back(Event::Scroll {
                        x: scroll_event.x,
                        y: scroll_event.y,
                    })
                }
                orbclient::EventOption::Key(key_event) => if key_event.pressed {
                    self.events.push_back(Event::KeyPressed(
                        KeyEvent::from_orbital_key_event(key_event),
                    ));
                } else {
                    self.events.push_back(Event::KeyReleased(
                        KeyEvent::from_orbital_key_event(key_event),
                    ));
                },
                orbclient::EventOption::Resize(resize_event) => {
                    self.redraw = true;
                    self.events.push_back(Event::Resize {
                        width: resize_event.width,
                        height: resize_event.height,
                    });
                }
                orbclient::EventOption::Quit(_quit_event) => {
                    self.running.set(false);
                }
                _ => (),
            };
        }
    }

    pub fn exec(&mut self) {
        'event: while self.running.get() {
            self.drain_events();
            self.draw_if_needed();
            self.drain_orbital_events();
        }
    }

    pub fn needs_redraw(&mut self) {
        self.redraw = true;
    }

    pub fn draw_if_needed(&mut self) {
        if self.redraw {
            self.draw();
            self.redraw = false;
        }
    }
}

pub struct WindowBuilder<'a> {
    rect: Rect,
    title: &'a str,
    font: Option<orbfont::Font>,
    theme: Option<Theme>,
    flags: Option<&'a [WindowFlag]>,
}

impl<'a> WindowBuilder<'a> {
    pub fn new(rect: Rect, title: &'a str) -> Self {
        WindowBuilder {
            rect: rect,
            title: title,
            font: orbfont::Font::find(None, None, None).ok(),
            theme: None,
            flags: None,
        }
    }

    pub fn font(mut self, font: orbfont::Font) -> Self {
        self.font = Some(font);
        self
    }

    pub fn theme(mut self, theme: Theme) -> Self {
        self.theme = Some(theme);
        self
    }

    pub fn flags(mut self, flags: &'a [WindowFlag]) -> Self {
        self.flags = Some(flags);
        self
    }

    pub fn build(self) -> Window {
        let (rect, title, font) = (self.rect, self.title, self.font);

        let flags = match self.flags {
            Some(flags) => flags,
            None => &[],
        };

        let inner =
            InnerWindow::new_flags(rect.x, rect.y, rect.width, rect.height, title, flags).unwrap();

        let theme = match self.theme {
            Some(theme) => theme,
            None => Theme::new(),
        };

        let mut events = VecDeque::new();
        events.push_back(Event::Init);

        Window {
            inner: RefCell::new(inner),
            font: font,
            widgets: RefCell::new(Vec::new()),
            running: Cell::new(true),
            theme: theme,
            resize_callback: RefCell::new(None),
            mouse_point: Point::new(0, 0),
            mouse_left: false,
            mouse_right: false,
            mouse_middle: false,
            events: events,
            redraw: true,
            focus_manager: FocusManager::new(),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(core)]

extern crate deuterium;
extern crate time;

use deuterium::*;

#[macro_export]
macro_rules! assert_sql {
    ($query:expr, $s:expr) => (
        assert_eq!($query.to_final_sql(&mut SqlContext::new(Box::new(sql::PostgreSqlAdapter))).as_slice(), $s)
    )
}

mod select;
mod where_;
mod order;
mod join;
mod group_by;
mod insert;
mod update;
mod delete;
mod placeholder;

#[test]
fn select_order() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query: SelectQuery<(String,), LimitOne, ()> = jedi_table.select_1(&name)
        .first().order_by(&name);

    assert_sql!(query, "SELECT name FROM jedi ORDER BY name ASC LIMIT 1;");

}

#[test]
fn select_left_join() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query = jedi_table.select_all().left_join(&jedi_table.alias("j"), name.is(name.clone()));
    assert_sql!(query, "SELECT * FROM jedi LEFT JOIN jedi AS j ON name = name;");

}<commit_msg>fix(lib): Modernize String to slice conversion<commit_after>extern crate deuterium;
extern crate time;

use deuterium::*;

#[macro_export]
macro_rules! assert_sql {
    ($query:expr, $s:expr) => (
        assert_eq!(&$query.to_final_sql(&mut SqlContext::new(Box::new(sql::PostgreSqlAdapter))), $s)
    )
}

mod select;
mod where_;
mod order;
mod join;
mod group_by;
mod insert;
mod update;
mod delete;
mod placeholder;

#[test]
fn select_order() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query: SelectQuery<(String,), LimitOne, ()> = jedi_table.select_1(&name)
        .first().order_by(&name);

    assert_sql!(query, "SELECT name FROM jedi ORDER BY name ASC LIMIT 1;");

}

#[test]
fn select_left_join() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query = jedi_table.select_all().left_join(&jedi_table.alias("j"), name.is(name.clone()));
    assert_sql!(query, "SELECT * FROM jedi LEFT JOIN jedi AS j ON name = name;");

}
<|endoftext|>


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

use std::cast;
use std::libc::{c_int, size_t, ssize_t};
use std::ptr;
use std::rt::BlockedTask;
use std::rt::local::Local;
use std::rt::sched::Scheduler;

use super::{UvError, Buf, slice_to_uv_buf, Request, wait_until_woken_after,
            ForbidUnwind};
use uvll;

// This is a helper structure which is intended to get embedded into other
// Watcher structures. This structure will retain a handle to the underlying
// uv_stream_t instance, and all I/O operations assume that it's already located
// on the appropriate scheduler.
pub struct StreamWatcher {
    handle: *uvll::uv_stream_t,

    // Cache the last used uv_write_t so we don't have to allocate a new one on
    // every call to uv_write(). Ideally this would be a stack-allocated
    // structure, but currently we don't have mappings for all the structures
    // defined in libuv, so we're foced to malloc this.
    priv last_write_req: Option<Request>,
}

struct ReadContext {
    buf: Option<Buf>,
    result: ssize_t,
    task: Option<BlockedTask>,
}

struct WriteContext {
    result: c_int,
    task: Option<BlockedTask>,
}

impl StreamWatcher {
    // Creates a new helper structure which should be then embedded into another
    // watcher. This provides the generic read/write methods on streams.
    //
    // This structure will *not* close the stream when it is dropped. It is up
    // to the enclosure structure to be sure to call the close method (which
    // will block the task). Note that this is also required to prevent memory
    // leaks.
    //
    // It should also be noted that the `data` field of the underlying uv handle
    // will be manipulated on each of the methods called on this watcher.
    // Wrappers should ensure to always reset the field to an appropriate value
    // if they rely on the field to perform an action.
    pub fn new(stream: *uvll::uv_stream_t) -> StreamWatcher {
        StreamWatcher {
            handle: stream,
            last_write_req: None,
        }
    }

    pub fn read(&mut self, buf: &mut [u8]) -> Result<uint, UvError> {
        // This read operation needs to get canceled on an unwind via libuv's
        // uv_read_stop function
        let _f = ForbidUnwind::new("stream read");

        // Send off the read request, but don't block until we're sure that the
        // read request is queued.
        match unsafe {
            uvll::uv_read_start(self.handle, alloc_cb, read_cb)
        } {
            0 => {
                let mut rcx = ReadContext {
                    buf: Some(slice_to_uv_buf(buf)),
                    result: 0,
                    task: None,
                };
                do wait_until_woken_after(&mut rcx.task) {
                    unsafe {
                        uvll::set_data_for_uv_handle(self.handle, &rcx)
                    }
                }
                match rcx.result {
                    n if n < 0 => Err(UvError(n as c_int)),
                    n => Ok(n as uint),
                }
            }
            n => Err(UvError(n))
        }
    }

    pub fn write(&mut self, buf: &[u8]) -> Result<(), UvError> {
        // The ownership of the write request is dubious if this function
        // unwinds. I believe that if the write_cb fails to re-schedule the task
        // then the write request will be leaked.
        let _f = ForbidUnwind::new("stream write");

        // Prepare the write request, either using a cached one or allocating a
        // new one
        let mut req = match self.last_write_req.take() {
            Some(req) => req, None => Request::new(uvll::UV_WRITE),
        };
        req.set_data(ptr::null::<()>());

        // Send off the request, but be careful to not block until we're sure
        // that the write reqeust is queued. If the reqeust couldn't be queued,
        // then we should return immediately with an error.
        match unsafe {
            uvll::uv_write(req.handle, self.handle, [slice_to_uv_buf(buf)],
                           write_cb)
        } {
            0 => {
                let mut wcx = WriteContext { result: 0, task: None, };
                req.defuse(); // uv callback now owns this request

                do wait_until_woken_after(&mut wcx.task) {
                    req.set_data(&wcx);
                }
                self.last_write_req = Some(Request::wrap(req.handle));
                match wcx.result {
                    0 => Ok(()),
                    n => Err(UvError(n)),
                }
            }
            n => Err(UvError(n)),
        }
    }
}

// This allocation callback expects to be invoked once and only once. It will
// unwrap the buffer in the ReadContext stored in the stream and return it. This
// will fail if it is called more than once.
extern fn alloc_cb(stream: *uvll::uv_stream_t, _hint: size_t, buf: *mut Buf) {
    uvdebug!("alloc_cb");
    unsafe {
        let rcx: &mut ReadContext =
            cast::transmute(uvll::get_data_for_uv_handle(stream));
        *buf = rcx.buf.take().expect("stream alloc_cb called more than once");
    }
}

// When a stream has read some data, we will always forcibly stop reading and
// return all the data read (even if it didn't fill the whole buffer).
extern fn read_cb(handle: *uvll::uv_stream_t, nread: ssize_t, _buf: *Buf) {
    uvdebug!("read_cb {}", nread);
    assert!(nread != uvll::ECANCELED as ssize_t);
    let rcx: &mut ReadContext = unsafe {
        cast::transmute(uvll::get_data_for_uv_handle(handle))
    };
    // Stop reading so that no read callbacks are
    // triggered before the user calls `read` again.
    // XXX: Is there a performance impact to calling
    // stop here?
    unsafe { assert_eq!(uvll::uv_read_stop(handle), 0); }
    rcx.result = nread;

    let scheduler: ~Scheduler = Local::take();
    scheduler.resume_blocked_task_immediately(rcx.task.take_unwrap());
}

// Unlike reading, the WriteContext is stored in the uv_write_t request. Like
// reading, however, all this does is wake up the blocked task after squirreling
// away the error code as a result.
extern fn write_cb(req: *uvll::uv_write_t, status: c_int) {
    let mut req = Request::wrap(req);
    assert!(status != uvll::ECANCELED);
    // Remember to not free the request because it is re-used between writes on
    // the same stream.
    let wcx: &mut WriteContext = unsafe { req.get_data() };
    wcx.result = status;
    req.defuse();

    let sched: ~Scheduler = Local::take();
    sched.resume_blocked_task_immediately(wcx.task.take_unwrap());
}
<commit_msg>auto merge of #10646 : alexcrichton/rust/issue-10645, r=luqmana<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::cast;
use std::libc::{c_int, size_t, ssize_t};
use std::ptr;
use std::rt::BlockedTask;
use std::rt::local::Local;
use std::rt::sched::Scheduler;

use super::{UvError, Buf, slice_to_uv_buf, Request, wait_until_woken_after,
            ForbidUnwind};
use uvll;

// This is a helper structure which is intended to get embedded into other
// Watcher structures. This structure will retain a handle to the underlying
// uv_stream_t instance, and all I/O operations assume that it's already located
// on the appropriate scheduler.
pub struct StreamWatcher {
    handle: *uvll::uv_stream_t,

    // Cache the last used uv_write_t so we don't have to allocate a new one on
    // every call to uv_write(). Ideally this would be a stack-allocated
    // structure, but currently we don't have mappings for all the structures
    // defined in libuv, so we're foced to malloc this.
    priv last_write_req: Option<Request>,
}

struct ReadContext {
    buf: Option<Buf>,
    result: ssize_t,
    task: Option<BlockedTask>,
}

struct WriteContext {
    result: c_int,
    task: Option<BlockedTask>,
}

impl StreamWatcher {
    // Creates a new helper structure which should be then embedded into another
    // watcher. This provides the generic read/write methods on streams.
    //
    // This structure will *not* close the stream when it is dropped. It is up
    // to the enclosure structure to be sure to call the close method (which
    // will block the task). Note that this is also required to prevent memory
    // leaks.
    //
    // It should also be noted that the `data` field of the underlying uv handle
    // will be manipulated on each of the methods called on this watcher.
    // Wrappers should ensure to always reset the field to an appropriate value
    // if they rely on the field to perform an action.
    pub fn new(stream: *uvll::uv_stream_t) -> StreamWatcher {
        StreamWatcher {
            handle: stream,
            last_write_req: None,
        }
    }

    pub fn read(&mut self, buf: &mut [u8]) -> Result<uint, UvError> {
        // This read operation needs to get canceled on an unwind via libuv's
        // uv_read_stop function
        let _f = ForbidUnwind::new("stream read");

        let mut rcx = ReadContext {
            buf: Some(slice_to_uv_buf(buf)),
            result: 0,
            task: None,
        };
        // When reading a TTY stream on windows, libuv will invoke alloc_cb
        // immediately as part of the call to alloc_cb. What this means is that
        // we must be ready for this to happen (by setting the data in the uv
        // handle). In theory this otherwise doesn't need to happen until after
        // the read is succesfully started.
        unsafe {
            uvll::set_data_for_uv_handle(self.handle, &rcx)
        }

        // Send off the read request, but don't block until we're sure that the
        // read request is queued.
        match unsafe {
            uvll::uv_read_start(self.handle, alloc_cb, read_cb)
        } {
            0 => {
                wait_until_woken_after(&mut rcx.task, || {});
                match rcx.result {
                    n if n < 0 => Err(UvError(n as c_int)),
                    n => Ok(n as uint),
                }
            }
            n => Err(UvError(n))
        }
    }

    pub fn write(&mut self, buf: &[u8]) -> Result<(), UvError> {
        // The ownership of the write request is dubious if this function
        // unwinds. I believe that if the write_cb fails to re-schedule the task
        // then the write request will be leaked.
        let _f = ForbidUnwind::new("stream write");

        // Prepare the write request, either using a cached one or allocating a
        // new one
        let mut req = match self.last_write_req.take() {
            Some(req) => req, None => Request::new(uvll::UV_WRITE),
        };
        req.set_data(ptr::null::<()>());

        // Send off the request, but be careful to not block until we're sure
        // that the write reqeust is queued. If the reqeust couldn't be queued,
        // then we should return immediately with an error.
        match unsafe {
            uvll::uv_write(req.handle, self.handle, [slice_to_uv_buf(buf)],
                           write_cb)
        } {
            0 => {
                let mut wcx = WriteContext { result: 0, task: None, };
                req.defuse(); // uv callback now owns this request

                do wait_until_woken_after(&mut wcx.task) {
                    req.set_data(&wcx);
                }
                self.last_write_req = Some(Request::wrap(req.handle));
                match wcx.result {
                    0 => Ok(()),
                    n => Err(UvError(n)),
                }
            }
            n => Err(UvError(n)),
        }
    }
}

// This allocation callback expects to be invoked once and only once. It will
// unwrap the buffer in the ReadContext stored in the stream and return it. This
// will fail if it is called more than once.
extern fn alloc_cb(stream: *uvll::uv_stream_t, _hint: size_t, buf: *mut Buf) {
    uvdebug!("alloc_cb");
    unsafe {
        let rcx: &mut ReadContext =
            cast::transmute(uvll::get_data_for_uv_handle(stream));
        *buf = rcx.buf.take().expect("stream alloc_cb called more than once");
    }
}

// When a stream has read some data, we will always forcibly stop reading and
// return all the data read (even if it didn't fill the whole buffer).
extern fn read_cb(handle: *uvll::uv_stream_t, nread: ssize_t, _buf: *Buf) {
    uvdebug!("read_cb {}", nread);
    assert!(nread != uvll::ECANCELED as ssize_t);
    let rcx: &mut ReadContext = unsafe {
        cast::transmute(uvll::get_data_for_uv_handle(handle))
    };
    // Stop reading so that no read callbacks are
    // triggered before the user calls `read` again.
    // XXX: Is there a performance impact to calling
    // stop here?
    unsafe { assert_eq!(uvll::uv_read_stop(handle), 0); }
    rcx.result = nread;

    let scheduler: ~Scheduler = Local::take();
    scheduler.resume_blocked_task_immediately(rcx.task.take_unwrap());
}

// Unlike reading, the WriteContext is stored in the uv_write_t request. Like
// reading, however, all this does is wake up the blocked task after squirreling
// away the error code as a result.
extern fn write_cb(req: *uvll::uv_write_t, status: c_int) {
    let mut req = Request::wrap(req);
    assert!(status != uvll::ECANCELED);
    // Remember to not free the request because it is re-used between writes on
    // the same stream.
    let wcx: &mut WriteContext = unsafe { req.get_data() };
    wcx.result = status;
    req.defuse();

    let sched: ~Scheduler = Local::take();
    sched.resume_blocked_task_immediately(wcx.task.take_unwrap());
}
<|endoftext|>


<commit_before>use std::mem;
use std::ops;
use std::ptr;
use std::slice;
use std::iter;

use nodrop::NoDrop;

use num_traits::{Unsigned, Zero, One};

pub struct OverflowError<T1, T2>(pub T1, pub T2);

#[derive(Debug)]
pub enum InsertError<T1, T2> {
    Overflow(T1, T2),
    OutOfBounds(T1, T2)
}

pub unsafe trait Array {
    type Item;
    type Index: Index;
    fn as_ptr(&self) -> *const Self::Item;
    fn as_mut_ptr(&mut self) -> *mut Self::Item;
    fn capacity(&self) -> usize;
}

pub trait Index : Unsigned + ops::AddAssign + ops::SubAssign + Copy {
    fn as_usize(self) -> usize;
    fn from_usize(value: usize) -> Self;
}

macro_rules! impl_index {
    ($index_type:ty) => (
        impl Index for $index_type {
            fn as_usize(self) -> usize {
                self as usize
            }

            fn from_usize(value: usize) -> Self {
                value as $index_type
            }
        }
    )
}

impl_index!(u8);
impl_index!(u16);
impl_index!(u32);
impl_index!(usize);

macro_rules! impl_array {
    ($index_type:ty, $len:expr ) => (
        unsafe impl<T> Array for [T; $len] {
            type Item = T;
            type Index = $index_type;
            #[inline(always)]
            fn as_ptr(&self) -> *const T {
                self as *const _ as *const _
            }

            #[inline(always)]
            fn as_mut_ptr(&mut self) -> *mut T {
                self as *mut _ as *mut _
            }

            #[inline(always)]
            fn capacity(&self) -> usize {
                $len
            }
        }
    )
}

macro_rules! impl_array_many {
    ($index_type:ty, $($len:expr),+) => (
        $(
            impl_array!($index_type, $len);
        )*
    );
}

impl_array_many!(u8, 1, 2, 7, 31, 256);

pub struct LockstepArray<A1: Array, A2: Array> {
    len: A1::Index,
    array1: NoDrop<A1>,
    array2: NoDrop<A2>
}

impl<A1, A2> LockstepArray<A1, A2> where A1: Array, A2: Array {
    pub fn new() -> LockstepArray<A1, A2> {
        LockstepArray {
            len: Zero::zero(),
            array1: NoDrop::new(unsafe {mem::uninitialized()}),
            array2: NoDrop::new(unsafe {mem::uninitialized()})
        }
    }

    pub fn from_arrays<B1, B2>(array1: B1, array2: B2) -> LockstepArray<A1, A2>
        where B1: Array<Item=A1::Item>, B2: Array<Item=A2::Item> {
        let mut lockstep = LockstepArray::<A1, A2>::new();
        // Eventually these will be encoded into the type system
        assert!(array1.capacity() <= lockstep.array1.capacity());
        assert!(array2.capacity() <= lockstep.array2.capacity());
        assert_eq!(array1.capacity(), array2.capacity());
        let len = A1::Index::from_usize(array1.capacity());
        unsafe {
            ptr::copy_nonoverlapping(array1.as_ptr(),
                                     lockstep.array1.as_mut_ptr(),
                                     array1.capacity());
            mem::forget(array1);
            ptr::copy_nonoverlapping(array2.as_ptr(),
                                     lockstep.array2.as_mut_ptr(),
                                     array2.capacity());
            mem::forget(array2);
        }
        lockstep.len = len;
        lockstep
    }

    pub fn push(&mut self, item1: A1::Item, item2: A2::Item)
                -> Result<(), OverflowError<A1::Item, A2::Item>> {
        if self.len.as_usize() == self.array1.capacity() {
            return Err(OverflowError(item1, item2));
        }
        unsafe {
            let p1 = self.array1.as_mut_ptr();
            ptr::write(p1.offset(self.len.as_usize() as isize), item1);
            let p2 = self.array2.as_mut_ptr();
            ptr::write(p2.offset(self.len.as_usize() as isize), item2);
        }
        self.len += One::one();
        Ok(())
    }

    pub fn pop(&mut self) -> Option<(A1::Item, A2::Item)> {
        if self.len == Zero::zero() {
            None
        } else {
            unsafe {
                // Calculate item 1's pointer
                let src1 = self.array1.as_mut_ptr()
                    .offset(self.len.as_usize() as isize);
                // Move item 1 out of the pointer
                let item1 = ptr::read(src1);
                // Calculate item 1's pointer
                let src2 = self.array2.as_mut_ptr()
                    .offset(self.len.as_usize() as isize);
                // Move item 1 out of the pointer
                let item2 = ptr::read(src2);
                // Update length
                self.len -= One::one();
                Some((item1, item2))
            }
        }
    }

    pub fn insert(&mut self, index: usize, item1: A1::Item, item2: A2::Item)
                  -> Result<(), InsertError<A1::Item, A2::Item>> {
        if index > self.len.as_usize() {
            Err(InsertError::OutOfBounds(item1, item2))
        } else if self.len.as_usize() == self.array1.capacity() {
            Err(InsertError::Overflow(item1, item2))
        } else {
            unsafe {
                // TODO: Tricky math, check indices and such
                let dest1 = self.array1.as_mut_ptr().offset(index as isize);
                ptr::copy(dest1, dest1.offset(1), self.len.as_usize() - index);
                ptr::write(dest1, item1);
                let dest2 = self.array2.as_mut_ptr().offset(index as isize);
                ptr::copy(dest2, dest2.offset(1), self.len.as_usize() - index);
                ptr::write(dest2, item2);
            }
            self.len += One::one();
            Ok(())
        }
    }

    pub fn remove(&mut self, index: usize) -> Option<(A1::Item, A2::Item)> {
        if index >= self.len.as_usize() {
            None
        } else {
            let item1;
            let item2;
            unsafe {
                // Calculate item 1's pointer
                let src1 = self.array1.as_mut_ptr().offset(index as isize);
                // Move item 1 out of the pointer
                item1 = ptr::read(src1);
                // Shift down array 1 down by 1
                // Is self.len - index correct?
                ptr::copy(src1.offset(1), src1, self.len.as_usize() - index);
                // Calculate item 1's pointer
                let src2 = self.array2.as_mut_ptr().offset(index as isize);
                // Move item 1 out of the pointer
                item2 = ptr::read(src2);
                // Shift down array 1 down by 1
                // Is self.len - index correct?
                ptr::copy(src2, src2.offset(1), self.len.as_usize() - index);
                // Update length
                self.len -= One::one();
            }
            Some((item1, item2))
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len != Zero::zero()
    }

    pub fn len(&self) -> usize {
        self.len.as_usize()
    }

    pub fn get(&self, index: usize) -> Option<(&A1::Item, &A2::Item)> {
        if index >= self.len.as_usize() {
            None
        } else {
            let item1 = unsafe {
                &*self.array1.as_ptr().offset(index as isize)
            };
            let item2 = unsafe {
                &*self.array2.as_ptr().offset(index as isize)
            };
            Some((item1, item2))
        }
    }

    pub fn array1(&self) -> &[A1::Item] {
        unsafe {
            let ptr = self.array1.as_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts(ptr, len)
        }
    }

    pub fn array2(&self) -> &[A2::Item] {
        unsafe {
            let ptr = self.array2.as_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts(ptr, len)
        }
    }

    pub fn array1_mut(&mut self) -> &mut [A1::Item] {
        unsafe {
            let ptr = self.array1.as_mut_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts_mut(ptr, len)
        }
    }

    pub fn array2_mut(&mut self) -> &mut [A2::Item] {
        unsafe {
            let ptr = self.array2.as_mut_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts_mut(ptr, len)
        }
    }

    pub fn capacity(&self) -> usize {
        self.array1.capacity()
    }
}

impl<A1, A2> Default for LockstepArray<A1, A2> where A1: Array, A2: Array {
    fn default() -> Self {
        Self::new()
    }
}

impl<A1, A2> IntoIterator for LockstepArray<A1, A2> where A1: Array, A2: Array {
    type Item = (A1::Item, A2::Item);
    type IntoIter = IntoIter<A1, A2>;
    fn into_iter(self) -> Self::IntoIter {
        let LockstepArray { len, array1, array2 } = self;
        IntoIter {
            len: len.as_usize(),
            array1: array1,
            array2: array2,
            pos: 0
        }
    }
}

pub struct IntoIter<A1: Array, A2: Array> {
    len: usize,
    array1: NoDrop<A1>,
    array2: NoDrop<A2>,
    pos: usize
}

impl<A1: Array, A2: Array> Iterator for IntoIter<A1, A2> {
    type Item = (A1::Item, A2::Item);
    fn next(&mut self) -> Option<Self::Item> {
        if self.pos == self.len {
            None
        } else {
            unsafe {
                let ptr1 = self.array1.as_mut_ptr().offset(self.pos as isize);
                let item1 = ptr::read(ptr1);
                let ptr2 = self.array2.as_mut_ptr().offset(self.pos as isize);
                let item2 = ptr::read(ptr2);
                self.pos += 1;
                Some((item1, item2))
            }
        }
    }
}

#[test]
fn test_into_iter() {
    let mut locksteparray = LockstepArray::<[u8; 7], [u8; 7]>::new();
    locksteparray.insert(0, 4, 5).unwrap();
    locksteparray.insert(1, 3, 4).unwrap();
    let mut iter = locksteparray.into_iter();
    assert_eq!(iter.next(), Some((4, 5)));
    assert_eq!(iter.next(), Some((3, 4)));
    assert_eq!(iter.next(), None);
}
<commit_msg>Correct LockstepArray::remove() implementation<commit_after>use std::mem;
use std::ops;
use std::ptr;
use std::slice;
use std::iter;

use nodrop::NoDrop;

use num_traits::{Unsigned, Zero, One};

#[derive(Debug)]
pub struct OverflowError<T1, T2>(pub T1, pub T2);

#[derive(Debug)]
pub enum InsertError<T1, T2> {
    Overflow(T1, T2),
    OutOfBounds(T1, T2)
}

pub unsafe trait Array {
    type Item;
    type Index: Index;
    fn as_ptr(&self) -> *const Self::Item;
    fn as_mut_ptr(&mut self) -> *mut Self::Item;
    fn capacity(&self) -> usize;
}

pub trait Index : Unsigned + ops::AddAssign + ops::SubAssign + Copy {
    fn as_usize(self) -> usize;
    fn from_usize(value: usize) -> Self;
}

macro_rules! impl_index {
    ($index_type:ty) => (
        impl Index for $index_type {
            fn as_usize(self) -> usize {
                self as usize
            }

            fn from_usize(value: usize) -> Self {
                value as $index_type
            }
        }
    )
}

impl_index!(u8);
impl_index!(u16);
impl_index!(u32);
impl_index!(usize);

macro_rules! impl_array {
    ($index_type:ty, $len:expr ) => (
        unsafe impl<T> Array for [T; $len] {
            type Item = T;
            type Index = $index_type;
            #[inline(always)]
            fn as_ptr(&self) -> *const T {
                self as *const _ as *const _
            }

            #[inline(always)]
            fn as_mut_ptr(&mut self) -> *mut T {
                self as *mut _ as *mut _
            }

            #[inline(always)]
            fn capacity(&self) -> usize {
                $len
            }
        }
    )
}

macro_rules! impl_array_many {
    ($index_type:ty, $($len:expr),+) => (
        $(
            impl_array!($index_type, $len);
        )*
    );
}

impl_array_many!(u8, 1, 2, 7, 31, 256);

pub struct LockstepArray<A1: Array, A2: Array> {
    len: A1::Index,
    array1: NoDrop<A1>,
    array2: NoDrop<A2>
}

impl<A1, A2> LockstepArray<A1, A2> where A1: Array, A2: Array {
    pub fn new() -> LockstepArray<A1, A2> {
        LockstepArray {
            len: Zero::zero(),
            array1: NoDrop::new(unsafe {mem::uninitialized()}),
            array2: NoDrop::new(unsafe {mem::uninitialized()})
        }
    }

    pub fn from_arrays<B1, B2>(array1: B1, array2: B2) -> LockstepArray<A1, A2>
        where B1: Array<Item=A1::Item>, B2: Array<Item=A2::Item> {
        let mut lockstep = LockstepArray::<A1, A2>::new();
        // Eventually these will be encoded into the type system
        assert!(array1.capacity() <= lockstep.array1.capacity());
        assert!(array2.capacity() <= lockstep.array2.capacity());
        assert_eq!(array1.capacity(), array2.capacity());
        let len = A1::Index::from_usize(array1.capacity());
        unsafe {
            ptr::copy_nonoverlapping(array1.as_ptr(),
                                     lockstep.array1.as_mut_ptr(),
                                     array1.capacity());
            mem::forget(array1);
            ptr::copy_nonoverlapping(array2.as_ptr(),
                                     lockstep.array2.as_mut_ptr(),
                                     array2.capacity());
            mem::forget(array2);
        }
        lockstep.len = len;
        lockstep
    }

    pub fn push(&mut self, item1: A1::Item, item2: A2::Item)
                -> Result<(), OverflowError<A1::Item, A2::Item>> {
        if self.len.as_usize() == self.array1.capacity() {
            return Err(OverflowError(item1, item2));
        }
        unsafe {
            let p1 = self.array1.as_mut_ptr();
            ptr::write(p1.offset(self.len.as_usize() as isize), item1);
            let p2 = self.array2.as_mut_ptr();
            ptr::write(p2.offset(self.len.as_usize() as isize), item2);
        }
        self.len += One::one();
        Ok(())
    }

    pub fn pop(&mut self) -> Option<(A1::Item, A2::Item)> {
        if self.len == Zero::zero() {
            None
        } else {
            unsafe {
                // Calculate item 1's pointer
                let src1 = self.array1.as_mut_ptr()
                    .offset(self.len.as_usize() as isize);
                // Move item 1 out of the pointer
                let item1 = ptr::read(src1);
                // Calculate item 1's pointer
                let src2 = self.array2.as_mut_ptr()
                    .offset(self.len.as_usize() as isize);
                // Move item 1 out of the pointer
                let item2 = ptr::read(src2);
                // Update length
                self.len -= One::one();
                Some((item1, item2))
            }
        }
    }

    pub fn insert(&mut self, index: usize, item1: A1::Item, item2: A2::Item)
                  -> Result<(), InsertError<A1::Item, A2::Item>> {
        if index > self.len.as_usize() {
            Err(InsertError::OutOfBounds(item1, item2))
        } else if self.len.as_usize() == self.array1.capacity() {
            Err(InsertError::Overflow(item1, item2))
        } else {
            unsafe {
                // TODO: Tricky math, check indices and such
                let dest1 = self.array1.as_mut_ptr().offset(index as isize);
                ptr::copy(dest1, dest1.offset(1), self.len.as_usize() - index);
                ptr::write(dest1, item1);
                let dest2 = self.array2.as_mut_ptr().offset(index as isize);
                ptr::copy(dest2, dest2.offset(1), self.len.as_usize() - index);
                ptr::write(dest2, item2);
            }
            self.len += One::one();
            Ok(())
        }
    }

    pub fn remove(&mut self, index: usize) -> Option<(A1::Item, A2::Item)> {
        if index >= self.len.as_usize() {
            None
        } else {
            let item1;
            let item2;
            unsafe {
                // Calculate item 1's pointer
                let src1 = self.array1.as_mut_ptr().offset(index as isize);
                // Move item 1 out of the pointer
                item1 = ptr::read(src1);
                // Shift down array 1 down by 1
                // Is self.len - index correct?
                ptr::copy(src1.offset(1), src1, self.len.as_usize() - index - 1);
                // Calculate item 1's pointer
                let src2 = self.array2.as_mut_ptr().offset(index as isize);
                // Move item 1 out of the pointer
                item2 = ptr::read(src2);
                // Shift down array 1 down by 1
                // Is self.len - index correct?
                ptr::copy(src2.offset(1), src2, self.len.as_usize() - index - 1);
                // Update length
                self.len -= One::one();
            }
            Some((item1, item2))
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len != Zero::zero()
    }

    pub fn len(&self) -> usize {
        self.len.as_usize()
    }

    pub fn get(&self, index: usize) -> Option<(&A1::Item, &A2::Item)> {
        if index >= self.len.as_usize() {
            None
        } else {
            let item1 = unsafe {
                &*self.array1.as_ptr().offset(index as isize)
            };
            let item2 = unsafe {
                &*self.array2.as_ptr().offset(index as isize)
            };
            Some((item1, item2))
        }
    }

    pub fn array1(&self) -> &[A1::Item] {
        unsafe {
            let ptr = self.array1.as_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts(ptr, len)
        }
    }

    pub fn array2(&self) -> &[A2::Item] {
        unsafe {
            let ptr = self.array2.as_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts(ptr, len)
        }
    }

    pub fn array1_mut(&mut self) -> &mut [A1::Item] {
        unsafe {
            let ptr = self.array1.as_mut_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts_mut(ptr, len)
        }
    }

    pub fn array2_mut(&mut self) -> &mut [A2::Item] {
        unsafe {
            let ptr = self.array2.as_mut_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts_mut(ptr, len)
        }
    }

    pub fn capacity(&self) -> usize {
        self.array1.capacity()
    }
}

impl<A1, A2> Default for LockstepArray<A1, A2> where A1: Array, A2: Array {
    fn default() -> Self {
        Self::new()
    }
}

impl<A1, A2> IntoIterator for LockstepArray<A1, A2> where A1: Array, A2: Array {
    type Item = (A1::Item, A2::Item);
    type IntoIter = IntoIter<A1, A2>;
    fn into_iter(self) -> Self::IntoIter {
        let LockstepArray { len, array1, array2 } = self;
        IntoIter {
            len: len.as_usize(),
            array1: array1,
            array2: array2,
            pos: 0
        }
    }
}

pub struct IntoIter<A1: Array, A2: Array> {
    len: usize,
    array1: NoDrop<A1>,
    array2: NoDrop<A2>,
    pos: usize
}

impl<A1: Array, A2: Array> Iterator for IntoIter<A1, A2> {
    type Item = (A1::Item, A2::Item);
    fn next(&mut self) -> Option<Self::Item> {
        if self.pos == self.len {
            None
        } else {
            unsafe {
                let ptr1 = self.array1.as_mut_ptr().offset(self.pos as isize);
                let item1 = ptr::read(ptr1);
                let ptr2 = self.array2.as_mut_ptr().offset(self.pos as isize);
                let item2 = ptr::read(ptr2);
                self.pos += 1;
                Some((item1, item2))
            }
        }
    }
}

#[test]
fn test_into_iter() {
    let mut locksteparray = LockstepArray::<[u8; 7], [u8; 7]>::new();
    locksteparray.insert(0, 4, 5).unwrap();
    locksteparray.insert(1, 3, 4).unwrap();
    let mut iter = locksteparray.into_iter();
    assert_eq!(iter.next(), Some((4, 5)));
    assert_eq!(iter.next(), Some((3, 4)));
    assert_eq!(iter.next(), None);
}

#[test]
fn test_remove() {
    let mut locksteparray = LockstepArray::<[u8; 7], [u8; 7]>::new();
    locksteparray.push(1, 2).unwrap();
    locksteparray.push(3, 4).unwrap();
    locksteparray.remove(0);
    assert_eq!(locksteparray.get(0), Some((&3, &4)));
    locksteparray.push(5, 6).unwrap();
    locksteparray.remove(1);
    assert_eq!(locksteparray.get(0), Some((&3, &4)));
}
<|endoftext|>