<commit_before>extern crate libc;
extern crate groonga_sys as ffi;
use std::mem;
use ffi::groonga as groonga;
use super::commandapi;

#[derive(Clone, Debug)]
pub struct LibGroonga {
    disposed: bool
}

impl LibGroonga {
    pub fn new() -> Result<LibGroonga, String> {
        let rc =  commandapi::groonga_init();
        if rc != groonga::GRN_SUCCESS {
            return Err("Couldn't initilize Groonga.".to_string())
        }
        Ok(LibGroonga{ disposed: false })
    }

    fn close(&mut self) -> Result<(), String> {
        if self.disposed {
            return Ok(())
        }
        let rc = commandapi::groonga_fin();
        if rc != groonga::GRN_SUCCESS {
            return Err("Couldn't finalized Groonga.".to_string())
        }
        self.disposed = true;
        Ok(())
    }
}

impl Drop for LibGroonga {
    fn drop(&mut self) {
        self.close().unwrap();
    }
}

#[derive(Clone, Debug)]
pub struct Context {
    ctx: *mut groonga::grn_ctx,
    disposed: bool
}

impl Context {
    pub fn new() -> Result<Context, String> {
        let ctx = commandapi::groonga_ctx_open(0);
        if ctx.is_null() {
            return Err("Couldn't create Groonga Context.".to_string())
        }
        Ok(Context{ ctx: ctx, disposed: false })
    }

    pub fn close(&mut self) -> Result<(), String> {
        if self.disposed {
            return Ok(())
        }
        let rc = commandapi::groonga_ctx_close(self.ctx);
        if rc != groonga::GRN_SUCCESS {
            return Err("Couldn't dispose Groonga Context.".to_string())
        }
        unsafe {
            self.ctx = mem::zeroed();
        }
        self.disposed = true;
        Ok(())
    }
}

#[derive(Clone, Debug)]
pub struct Database {
    ctx: *mut groonga::grn_ctx,
    disposed: bool
}

impl Database {
    pub fn new(ctx: Context) -> Database {
        Database{ctx: ctx.ctx, disposed: false}
    }

    pub fn uses(&mut self, dbpath: &str) {
        let _ = commandapi::groonga_db_use(self.ctx, dbpath);
    }

    fn close(&mut self) {
        if self.disposed {
            return
        }
        unsafe {
            self.ctx = mem::zeroed();
        }
        self.disposed = true;
    }
}

impl Drop for Database {
    fn drop(&mut self) {
        self.close()
    }
}

#[derive(Clone, Debug)]
pub struct Command {
    ctx: *mut groonga::grn_ctx,
    disposed: bool
}

impl Command {
    pub fn new(ctx: Context) -> Command {
        Command{ctx: ctx.ctx, disposed: false}
    }

    pub fn groonga_version() -> &'static str {
        commandapi::get_groonga_version()
    }

    pub fn execute(&mut self, command: &str) -> String {
        let result = commandapi::groonga_execute_command(self.ctx, command);
        match result {
            Ok(v) => v,
            Err(_) => "".to_string()
        }
    }

    fn close(&mut self) {
        if self.disposed {
            return
        }
        unsafe {
            self.ctx = mem::zeroed();
        }
        self.disposed = true;
    }
}

impl Drop for Command {
    fn drop(&mut self) {
        self.close()
    }
}

#[cfg(test)]
mod test {
    extern crate tempdir;
    use super::*;
    use self::tempdir::TempDir;

    fn setup_dbpath() -> String {
        let dbdir = TempDir::new("ruroonga");
        let dbname = "test.db";
        let mut dbpath_buf = dbdir.unwrap().into_path();
        dbpath_buf.push(dbname);
        let dbpath = match dbpath_buf.to_str() {
            Some(v) => v,
            None => panic!("Could not get temporary database path."),
        };

        dbpath.to_owned()
    }

    #[test]
    fn test_integration_test() {
        let groonga = LibGroonga::new();
        let is_success = match groonga {
            Ok(_) => true,
            Err(_) => false,
        };

        assert_eq!(true, is_success);

        let context = Context::new();
        let is_success = match context {
            Ok(_) => true,
            Err(_) => false,
        };

        assert_eq!(true, is_success);

        let ctx = match context {
            Ok(v) => v,
            Err(_) => panic!("Could not get context."),
        };

        let dbpath = setup_dbpath();
        let _ = Database::new(ctx.clone()).uses(&*dbpath);

        let grn_command = "table_create Users TABLE_HASH_KEY ShortText";
        let mut command = Command::new(ctx.clone());
        let table_create_result = command.execute(grn_command.clone());
        assert_eq!("true", table_create_result);

        let dump = "dump";
        let result = command.execute(dump.clone());
        let dumped_command = "table_create Users TABLE_HASH_KEY ShortText\n";
        assert!(
            dumped_command == result ||
            format!("{}\u{fffd}\u{7f}", dumped_command) == result
        );
    }
}
<commit_msg>test: Use more natual test case name<commit_after>extern crate libc;
extern crate groonga_sys as ffi;
use std::mem;
use ffi::groonga as groonga;
use super::commandapi;

#[derive(Clone, Debug)]
pub struct LibGroonga {
    disposed: bool
}

impl LibGroonga {
    pub fn new() -> Result<LibGroonga, String> {
        let rc =  commandapi::groonga_init();
        if rc != groonga::GRN_SUCCESS {
            return Err("Couldn't initilize Groonga.".to_string())
        }
        Ok(LibGroonga{ disposed: false })
    }

    fn close(&mut self) -> Result<(), String> {
        if self.disposed {
            return Ok(())
        }
        let rc = commandapi::groonga_fin();
        if rc != groonga::GRN_SUCCESS {
            return Err("Couldn't finalized Groonga.".to_string())
        }
        self.disposed = true;
        Ok(())
    }
}

impl Drop for LibGroonga {
    fn drop(&mut self) {
        self.close().unwrap();
    }
}

#[derive(Clone, Debug)]
pub struct Context {
    ctx: *mut groonga::grn_ctx,
    disposed: bool
}

impl Context {
    pub fn new() -> Result<Context, String> {
        let ctx = commandapi::groonga_ctx_open(0);
        if ctx.is_null() {
            return Err("Couldn't create Groonga Context.".to_string())
        }
        Ok(Context{ ctx: ctx, disposed: false })
    }

    pub fn close(&mut self) -> Result<(), String> {
        if self.disposed {
            return Ok(())
        }
        let rc = commandapi::groonga_ctx_close(self.ctx);
        if rc != groonga::GRN_SUCCESS {
            return Err("Couldn't dispose Groonga Context.".to_string())
        }
        unsafe {
            self.ctx = mem::zeroed();
        }
        self.disposed = true;
        Ok(())
    }
}

#[derive(Clone, Debug)]
pub struct Database {
    ctx: *mut groonga::grn_ctx,
    disposed: bool
}

impl Database {
    pub fn new(ctx: Context) -> Database {
        Database{ctx: ctx.ctx, disposed: false}
    }

    pub fn uses(&mut self, dbpath: &str) {
        let _ = commandapi::groonga_db_use(self.ctx, dbpath);
    }

    fn close(&mut self) {
        if self.disposed {
            return
        }
        unsafe {
            self.ctx = mem::zeroed();
        }
        self.disposed = true;
    }
}

impl Drop for Database {
    fn drop(&mut self) {
        self.close()
    }
}

#[derive(Clone, Debug)]
pub struct Command {
    ctx: *mut groonga::grn_ctx,
    disposed: bool
}

impl Command {
    pub fn new(ctx: Context) -> Command {
        Command{ctx: ctx.ctx, disposed: false}
    }

    pub fn groonga_version() -> &'static str {
        commandapi::get_groonga_version()
    }

    pub fn execute(&mut self, command: &str) -> String {
        let result = commandapi::groonga_execute_command(self.ctx, command);
        match result {
            Ok(v) => v,
            Err(_) => "".to_string()
        }
    }

    fn close(&mut self) {
        if self.disposed {
            return
        }
        unsafe {
            self.ctx = mem::zeroed();
        }
        self.disposed = true;
    }
}

impl Drop for Command {
    fn drop(&mut self) {
        self.close()
    }
}

#[cfg(test)]
mod test {
    extern crate tempdir;
    use super::*;
    use self::tempdir::TempDir;

    fn setup_dbpath() -> String {
        let dbdir = TempDir::new("ruroonga");
        let dbname = "test.db";
        let mut dbpath_buf = dbdir.unwrap().into_path();
        dbpath_buf.push(dbname);
        let dbpath = match dbpath_buf.to_str() {
            Some(v) => v,
            None => panic!("Could not get temporary database path."),
        };

        dbpath.to_owned()
    }

    #[test]
    fn integration_test() {
        let groonga = LibGroonga::new();
        let is_success = match groonga {
            Ok(_) => true,
            Err(_) => false,
        };

        assert_eq!(true, is_success);

        let context = Context::new();
        let is_success = match context {
            Ok(_) => true,
            Err(_) => false,
        };

        assert_eq!(true, is_success);

        let ctx = match context {
            Ok(v) => v,
            Err(_) => panic!("Could not get context."),
        };

        let dbpath = setup_dbpath();
        let _ = Database::new(ctx.clone()).uses(&*dbpath);

        let grn_command = "table_create Users TABLE_HASH_KEY ShortText";
        let mut command = Command::new(ctx.clone());
        let table_create_result = command.execute(grn_command.clone());
        assert_eq!("true", table_create_result);

        let dump = "dump";
        let result = command.execute(dump.clone());
        let dumped_command = "table_create Users TABLE_HASH_KEY ShortText\n";
        assert!(
            dumped_command == result ||
            format!("{}\u{fffd}\u{7f}", dumped_command) == result
        );
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate lanta;

use lanta::{cmd, Lanta, ModKey};
use lanta::errors::*;
use lanta::layout::*;

macro_rules! spawn {
    ($cmd:expr) => (::lanta::cmd::lazy::spawn(::std::process::Command::new($cmd)));
    ($cmd:expr, $($arg:expr),*) => {{
        let mut command = ::std::process::Command::new($cmd);
        $(
            command.arg($arg);
        )*
        ::lanta::cmd::lazy::spawn(command)
    }}
}

fn run() -> Result<()> {
    lanta::intiailize_logger()?;

    let modkey = ModKey::Mod4;
    let shift = ModKey::Shift;
    let mut keys = keys![
        ([modkey], XK_w, cmd::lazy::close_focused_window()),
        ([modkey], XK_j, cmd::lazy::focus_next()),
        ([modkey], XK_k, cmd::lazy::focus_previous()),
        ([modkey, shift], XK_j, cmd::lazy::shuffle_next()),
        ([modkey, shift], XK_k, cmd::lazy::shuffle_previous()),
        ([modkey], XK_Tab, cmd::lazy::layout_next()),
        ([modkey], XK_Return, spawn!("urxvt")),
        ([modkey], XK_c, spawn!("chrome")),
        ([modkey], XK_v, spawn!("code")),
        ([modkey], XK_b, spawn!("spotify --force-device-scale-factor=2")),
        ([modkey], XK_q, spawn!("change-wallpaper")),
        ([], XF86XK_MonBrightnessUp, spawn!("xbacklight", "-inc", "10")),
        ([], XF86XK_MonBrightnessDown, spawn!("xbacklight", "-dec", "10")),
        ([], XF86XK_AudioPrev, spawn!("playerctl", "previous")),
        ([], XF86XK_AudioPlay, spawn!("playerctl", "play-pause")),
        ([], XF86XK_AudioNext, spawn!("playerctl", "next")),
        ([], XF86XK_AudioRaiseVolume, spawn!("amixer", "-q", "set", "Master", "5%+")),
        ([], XF86XK_AudioLowerVolume, spawn!("amixer", "-q", "set", "Master", "5%-")),
        ([], XF86XK_AudioMute, spawn!("amixer", "-q", "set", "Master", "toggle")),
    ];

    let padding = 20;
    let layouts = vec![
        StackLayout::new("stack-padded", padding),
        StackLayout::new("stack", 0),
        TiledLayout::new("tiled", padding),
    ];

    let groups = groups!{
        keys,
        [
            ([modkey], XK_a, "chrome", "stack"),
            ([modkey], XK_s, "code", "stack"),
            ([modkey], XK_d, "term", "tiled"),
            ([modkey], XK_f, "misc", "tiled"),
        ]
    };

    Lanta::new(keys, groups, layouts)?.run();

    Ok(())
}

quick_main!(run);
<commit_msg>personal config: firefox instead of chrome<commit_after>#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate lanta;

use lanta::{cmd, Lanta, ModKey};
use lanta::errors::*;
use lanta::layout::*;

macro_rules! spawn {
    ($cmd:expr) => (::lanta::cmd::lazy::spawn(::std::process::Command::new($cmd)));
    ($cmd:expr, $($arg:expr),*) => {{
        let mut command = ::std::process::Command::new($cmd);
        $(
            command.arg($arg);
        )*
        ::lanta::cmd::lazy::spawn(command)
    }}
}

fn run() -> Result<()> {
    lanta::intiailize_logger()?;

    let modkey = ModKey::Mod4;
    let shift = ModKey::Shift;
    let mut keys = keys![
        ([modkey], XK_w, cmd::lazy::close_focused_window()),
        ([modkey], XK_j, cmd::lazy::focus_next()),
        ([modkey], XK_k, cmd::lazy::focus_previous()),
        ([modkey, shift], XK_j, cmd::lazy::shuffle_next()),
        ([modkey, shift], XK_k, cmd::lazy::shuffle_previous()),
        ([modkey], XK_Tab, cmd::lazy::layout_next()),
        ([modkey], XK_Return, spawn!("urxvt")),
        ([modkey], XK_c, spawn!("firefox")),
        ([modkey], XK_v, spawn!("code")),
        ([modkey], XK_b, spawn!("spotify --force-device-scale-factor=2")),
        ([modkey], XK_q, spawn!("change-wallpaper")),
        ([], XF86XK_MonBrightnessUp, spawn!("xbacklight", "-inc", "10")),
        ([], XF86XK_MonBrightnessDown, spawn!("xbacklight", "-dec", "10")),
        ([], XF86XK_AudioPrev, spawn!("playerctl", "previous")),
        ([], XF86XK_AudioPlay, spawn!("playerctl", "play-pause")),
        ([], XF86XK_AudioNext, spawn!("playerctl", "next")),
        ([], XF86XK_AudioRaiseVolume, spawn!("amixer", "-q", "set", "Master", "5%+")),
        ([], XF86XK_AudioLowerVolume, spawn!("amixer", "-q", "set", "Master", "5%-")),
        ([], XF86XK_AudioMute, spawn!("amixer", "-q", "set", "Master", "toggle")),
    ];

    let padding = 20;
    let layouts = vec![
        StackLayout::new("stack-padded", padding),
        StackLayout::new("stack", 0),
        TiledLayout::new("tiled", padding),
    ];

    let groups = groups!{
        keys,
        [
            ([modkey], XK_a, "chrome", "stack"),
            ([modkey], XK_s, "code", "stack"),
            ([modkey], XK_d, "term", "tiled"),
            ([modkey], XK_f, "misc", "tiled"),
        ]
    };

    Lanta::new(keys, groups, layouts)?.run();

    Ok(())
}

quick_main!(run);
<|endoftext|>


<commit_before>//! Implementations of the callbacks exposed by wlc.
//! These functions are the main entry points into Way Cooler from user action.
#![allow(deprecated)] // keysyms

use rustwlc::handle::{WlcOutput, WlcView};
use rustwlc::types::{ButtonState, KeyboardModifiers, KeyState, KeyboardLed, ScrollAxis, Size,
                     Point, Geometry, ResizeEdge, ViewState, VIEW_ACTIVATED, VIEW_RESIZING,
                     MOD_NONE, MOD_CTRL, RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM};
use rustwlc::input::{pointer, keyboard};

use super::keys::{self, KeyPress, KeyEvent};
use super::layout::{try_lock_tree, try_lock_action, Action, ContainerType, MovementError, TreeError};
use super::layout::commands::set_performing_action;
use super::lua::{self, LuaQuery};

/// If the event is handled by way-cooler
const EVENT_BLOCKED: bool = true;

/// If the event should be passed through to clients
const EVENT_PASS_THROUGH: bool = false;

const LEFT_CLICK: u32 = 0x110;
const RIGHT_CLICK: u32 = 0x111;

pub extern fn output_created(output: WlcOutput) -> bool {
    trace!("output_created: {:?}: {}", output, output.get_name());
    if let Ok(mut tree) = try_lock_tree() {
        tree.add_output(output).and_then(|_|{
            tree.switch_to_workspace(&"1")
        }).is_ok()
    } else {
        false
    }
}

pub extern fn output_destroyed(output: WlcOutput) {
    trace!("output_destroyed: {:?}", output);
}

pub extern fn output_focus(output: WlcOutput, focused: bool) {
    trace!("output_focus: {:?} focus={}", output, focused);
}

pub extern fn output_resolution(output: WlcOutput,
                                old_size_ptr: &Size, new_size_ptr: &Size) {
    trace!("output_resolution: {:?} from  {:?} to {:?}",
           output, *old_size_ptr, *new_size_ptr);
    // Update the resolution of the output and its children
    let scale = 1;
    output.set_resolution(*new_size_ptr, scale);
    if let Ok(mut tree) = try_lock_tree() {
        tree.layout_active_of(ContainerType::Output)
            .expect("Could not layout active output");
    }
}

pub extern fn view_created(view: WlcView) -> bool {
    trace!("view_created: {:?}: \"{}\"", view, view.get_title());
    if let Ok(mut tree) = try_lock_tree() {
        tree.add_view(view).and_then(|_| {
            if view.get_class() == "Background" {
                return Ok(())
            }
            tree.set_active_view(view).or_else(|_| {
                // We still want to focus on the window that appeared
                // Might need to change later, in case this focus grabbing
                // gets annoying / becomes a security issue.
                view.focus();
                Ok(())
            })
        }).is_ok()
    } else {
        false
    }
}

pub extern fn view_destroyed(view: WlcView) {
    trace!("view_destroyed: {:?}", view);
    if let Ok(mut tree) = try_lock_tree() {
        tree.remove_view(view).unwrap_or_else(|err| {
            match err {
                TreeError::ViewNotFound(_) => {},
                _ => {
                    error!("Error in view_destroyed: {:?}", err);
                }
            }
        });
    } else {
        error!("Could not delete view {:?}", view);
    }
}

pub extern fn view_focus(current: WlcView, focused: bool) {
    trace!("view_focus: {:?} {}", current, focused);
    current.set_state(VIEW_ACTIVATED, focused);
    if let Ok(mut tree) = try_lock_tree() {
        match tree.set_active_view(current) {
            Ok(_) => {},
            Err(err) => {
                error!("Could not set {:?} to be active view: {:?}", current, err);
            }
        }
    }
}

pub extern fn view_move_to_output(current: WlcView,
                                  o1: WlcOutput, o2: WlcOutput) {
    trace!("view_move_to_output: {:?}, {:?}, {:?}", current, o1, o2);
}

pub extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    trace!("Setting {:?} to state {:?}", view, state);
    view.set_state(state, handled);
}

pub extern fn view_request_move(view: WlcView, _dest: &Point) {
    if let Ok(mut tree) = try_lock_tree() {
        if let Err(err) = tree.set_active_view(view) {
            error!("view_request_move error: {:?}", err);
        }
    }
}

pub extern fn view_request_resize(view: WlcView, edge: ResizeEdge, point: &Point) {
    if let Ok(mut tree) = try_lock_tree() {
        match try_lock_action() {
            Ok(guard) => {
                if guard.is_some() {
                    if let Some(id) = tree.lookup_view(view) {
                        if let Err(err) = tree.resize_container(id, edge, *point) {
                            error!("Problem: Command returned error: {:#?}", err);
                        }
                    }
                }
            },
            _ => {}
        }
    }
}

pub extern fn keyboard_key(_view: WlcView, _time: u32, mods: &KeyboardModifiers,
                           key: u32, state: KeyState) -> bool {
    let empty_mods: KeyboardModifiers = KeyboardModifiers {
            mods: MOD_NONE,
            leds: KeyboardLed::empty()
    };
    let sym = keyboard::get_keysym_for_key(key, empty_mods);
    let press = KeyPress::new(mods.mods, sym);

    if state == KeyState::Pressed {
        if let Some(action) = keys::get(&press) {
            debug!("[key] Found an action for {}", press);
            match action {
                KeyEvent::Command(func) => {
                    func();
                },
                KeyEvent::Lua => {
                    match lua::send(LuaQuery::HandleKey(press)) {
                        Ok(_) => {},
                        Err(err) => {
                            // We may want to wait for Lua's reply from
                            // keypresses; for example if the table is tampered
                            // with or Lua is restarted or Lua has an error.
                            // ATM Lua asynchronously logs this but in the future
                            // an error popup/etc is a good idea.
                            error!("Error sending keypress: {:?}", err);
                        }
                    }
                }
            }
            return EVENT_BLOCKED
        }
    }

    return EVENT_PASS_THROUGH
}

pub extern fn view_request_geometry(_view: WlcView, _geometry: &Geometry) {
}

pub extern fn pointer_button(view: WlcView, _time: u32,
                         mods: &KeyboardModifiers, button: u32,
                             state: ButtonState, point: &Point) -> bool {
    if state == ButtonState::Pressed {
        if button == LEFT_CLICK && !view.is_root() {
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).ok();
                if mods.mods.contains(MOD_CTRL) {
                    let action = Action {
                        view: view,
                        grab: *point,
                        edges: ResizeEdge::empty()
                    };
                    set_performing_action(Some(action));
                }
            }
        } else if button == RIGHT_CLICK && !view.is_root() {
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).ok();
            }
            // TODO Make this set in the config file and read here.
            if mods.mods.contains(MOD_CTRL) {
                let action = Action {
                    view: view,
                    grab: *point,
                    edges: ResizeEdge::empty()
                };
                set_performing_action(Some(action));
                let geometry = view.get_geometry()
                    .expect("Could not get geometry of the view");
                let halfw = geometry.origin.x + geometry.size.w as i32 / 2;
                let halfh = geometry.origin.y + geometry.size.h as i32 / 2;

                {
                    let mut action: Action = try_lock_action().ok().and_then(|guard| *guard)
                        .unwrap_or(Action {
                            view: view,
                            grab: *point,
                            edges: ResizeEdge::empty()
                        });
                    let flag_x = if point.x < halfw {
                        RESIZE_LEFT
                    } else if point.x > halfw {
                        RESIZE_RIGHT
                    } else {
                        ResizeEdge::empty()
                    };

                    let flag_y = if point.y < halfh {
                        RESIZE_TOP
                    } else if point.y > halfh {
                        RESIZE_BOTTOM
                    } else {
                        ResizeEdge::empty()
                    };

                    action.edges = flag_x | flag_y;
                    set_performing_action(Some(action));
                }
                view.set_state(VIEW_RESIZING, true);
                return EVENT_BLOCKED
            }
        }
    } else {
        if let Ok(lock) = try_lock_action() {
            match *lock {
                Some(action) => {
                    let view = action.view;
                    if view.get_state().contains(VIEW_RESIZING) {
                        view.set_state(VIEW_RESIZING, false);
                    }
                },
                _ => {}
            }
        }
        set_performing_action(None);
    }
    EVENT_PASS_THROUGH
}

pub extern fn pointer_scroll(_view: WlcView, _time: u32,
                         _mods_ptr: &KeyboardModifiers, _axis: ScrollAxis,
                         _heights: [f64; 2]) -> bool {
    EVENT_PASS_THROUGH
}

pub extern fn pointer_motion(view: WlcView, _time: u32, point: &Point) -> bool {
    let mut result = EVENT_PASS_THROUGH;
    let mut maybe_action = None;
    {
        if let Ok(action_lock) = try_lock_action() {
            maybe_action = action_lock.clone();
        }
    }
    match maybe_action {
        None => result = EVENT_PASS_THROUGH,
        Some(action) => {
            if action.edges.bits() != 0 {
                if let Ok(mut tree) = try_lock_tree() {
                    // TODO Change to id of _view
                    // Need to implement a map of view to uuid first though...
                    if let Some(active_id) = tree.lookup_view(view) {
                        match tree.resize_container(active_id, action.edges, *point) {
                            // Return early here to not set the pointer
                            Ok(_) => return EVENT_BLOCKED,
                            Err(err) => error!("Error: {:#?}", err)
                        }
                    }
                }
            } else {
                if let Ok(mut tree) = try_lock_tree() {
                    match tree.try_drag_active(*point) {
                        Ok(_) => result = EVENT_BLOCKED,
                        Err(TreeError::PerformingAction(_)) |
                        Err(TreeError::Movement(MovementError::NotFloating(_))) => result = EVENT_PASS_THROUGH,
                        Err(err) => {
                            error!("Error: {:#?}", err);
                            result = EVENT_PASS_THROUGH
                        }
                    }
                }
            }
        }
    }
    pointer::set_position(*point);
    result
}

pub extern fn compositor_ready() {
    info!("Preparing compositor!");
    info!("Initializing Lua...");
    lua::init();
}

pub extern fn compositor_terminating() {
    info!("Compositor terminating!");
    lua::send(lua::LuaQuery::Terminate).ok();
    if let Ok(mut tree) = try_lock_tree() {
        if tree.destroy_tree().is_err() {
            error!("Could not destroy tree");
        }
    }

}

pub fn init() {
    use rustwlc::callback;

    callback::output_created(output_created);
    callback::output_destroyed(output_destroyed);
    callback::output_focus(output_focus);
    callback::output_resolution(output_resolution);
    callback::view_created(view_created);
    callback::view_destroyed(view_destroyed);
    callback::view_focus(view_focus);
    callback::view_move_to_output(view_move_to_output);
    callback::view_request_geometry(view_request_geometry);
    callback::view_request_state(view_request_state);
    callback::view_request_move(view_request_move);
    callback::view_request_resize(view_request_resize);
    callback::keyboard_key(keyboard_key);
    callback::pointer_button(pointer_button);
    callback::pointer_scroll(pointer_scroll);
    callback::pointer_motion(pointer_motion);
    callback::compositor_ready(compositor_ready);
    callback::compositor_terminate(compositor_terminating);
    trace!("Registered wlc callbacks");
}
<commit_msg>Can click to focus on views outside of the tree<commit_after>//! Implementations of the callbacks exposed by wlc.
//! These functions are the main entry points into Way Cooler from user action.
#![allow(deprecated)] // keysyms

use rustwlc::handle::{WlcOutput, WlcView};
use rustwlc::types::{ButtonState, KeyboardModifiers, KeyState, KeyboardLed, ScrollAxis, Size,
                     Point, Geometry, ResizeEdge, ViewState, VIEW_ACTIVATED, VIEW_RESIZING,
                     MOD_NONE, MOD_CTRL, RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM};
use rustwlc::input::{pointer, keyboard};

use super::keys::{self, KeyPress, KeyEvent};
use super::layout::{try_lock_tree, try_lock_action, Action, ContainerType, MovementError, TreeError};
use super::layout::commands::set_performing_action;
use super::lua::{self, LuaQuery};

/// If the event is handled by way-cooler
const EVENT_BLOCKED: bool = true;

/// If the event should be passed through to clients
const EVENT_PASS_THROUGH: bool = false;

const LEFT_CLICK: u32 = 0x110;
const RIGHT_CLICK: u32 = 0x111;

pub extern fn output_created(output: WlcOutput) -> bool {
    trace!("output_created: {:?}: {}", output, output.get_name());
    if let Ok(mut tree) = try_lock_tree() {
        tree.add_output(output).and_then(|_|{
            tree.switch_to_workspace(&"1")
        }).is_ok()
    } else {
        false
    }
}

pub extern fn output_destroyed(output: WlcOutput) {
    trace!("output_destroyed: {:?}", output);
}

pub extern fn output_focus(output: WlcOutput, focused: bool) {
    trace!("output_focus: {:?} focus={}", output, focused);
}

pub extern fn output_resolution(output: WlcOutput,
                                old_size_ptr: &Size, new_size_ptr: &Size) {
    trace!("output_resolution: {:?} from  {:?} to {:?}",
           output, *old_size_ptr, *new_size_ptr);
    // Update the resolution of the output and its children
    let scale = 1;
    output.set_resolution(*new_size_ptr, scale);
    if let Ok(mut tree) = try_lock_tree() {
        tree.layout_active_of(ContainerType::Output)
            .expect("Could not layout active output");
    }
}

pub extern fn view_created(view: WlcView) -> bool {
    trace!("view_created: {:?}: \"{}\"", view, view.get_title());
    if let Ok(mut tree) = try_lock_tree() {
        tree.add_view(view).and_then(|_| {
            if view.get_class() == "Background" {
                return Ok(())
            }
            tree.set_active_view(view).or_else(|_| {
                // We still want to focus on the window that appeared
                // Might need to change later, in case this focus grabbing
                // gets annoying / becomes a security issue.
                view.focus();
                Ok(())
            })
        }).is_ok()
    } else {
        false
    }
}

pub extern fn view_destroyed(view: WlcView) {
    trace!("view_destroyed: {:?}", view);
    if let Ok(mut tree) = try_lock_tree() {
        tree.remove_view(view).unwrap_or_else(|err| {
            match err {
                TreeError::ViewNotFound(_) => {},
                _ => {
                    error!("Error in view_destroyed: {:?}", err);
                }
            }
        });
    } else {
        error!("Could not delete view {:?}", view);
    }
}

pub extern fn view_focus(current: WlcView, focused: bool) {
    trace!("view_focus: {:?} {}", current, focused);
    current.set_state(VIEW_ACTIVATED, focused);
    if let Ok(mut tree) = try_lock_tree() {
        match tree.set_active_view(current) {
            Ok(_) => {},
            Err(err) => {
                error!("Could not set {:?} to be active view: {:?}", current, err);
            }
        }
    }
}

pub extern fn view_move_to_output(current: WlcView,
                                  o1: WlcOutput, o2: WlcOutput) {
    trace!("view_move_to_output: {:?}, {:?}, {:?}", current, o1, o2);
}

pub extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    trace!("Setting {:?} to state {:?}", view, state);
    view.set_state(state, handled);
}

pub extern fn view_request_move(view: WlcView, _dest: &Point) {
    if let Ok(mut tree) = try_lock_tree() {
        if let Err(err) = tree.set_active_view(view) {
            error!("view_request_move error: {:?}", err);
        }
    }
}

pub extern fn view_request_resize(view: WlcView, edge: ResizeEdge, point: &Point) {
    if let Ok(mut tree) = try_lock_tree() {
        match try_lock_action() {
            Ok(guard) => {
                if guard.is_some() {
                    if let Some(id) = tree.lookup_view(view) {
                        if let Err(err) = tree.resize_container(id, edge, *point) {
                            error!("Problem: Command returned error: {:#?}", err);
                        }
                    }
                }
            },
            _ => {}
        }
    }
}

pub extern fn keyboard_key(_view: WlcView, _time: u32, mods: &KeyboardModifiers,
                           key: u32, state: KeyState) -> bool {
    let empty_mods: KeyboardModifiers = KeyboardModifiers {
            mods: MOD_NONE,
            leds: KeyboardLed::empty()
    };
    let sym = keyboard::get_keysym_for_key(key, empty_mods);
    let press = KeyPress::new(mods.mods, sym);

    if state == KeyState::Pressed {
        if let Some(action) = keys::get(&press) {
            debug!("[key] Found an action for {}", press);
            match action {
                KeyEvent::Command(func) => {
                    func();
                },
                KeyEvent::Lua => {
                    match lua::send(LuaQuery::HandleKey(press)) {
                        Ok(_) => {},
                        Err(err) => {
                            // We may want to wait for Lua's reply from
                            // keypresses; for example if the table is tampered
                            // with or Lua is restarted or Lua has an error.
                            // ATM Lua asynchronously logs this but in the future
                            // an error popup/etc is a good idea.
                            error!("Error sending keypress: {:?}", err);
                        }
                    }
                }
            }
            return EVENT_BLOCKED
        }
    }

    return EVENT_PASS_THROUGH
}

pub extern fn view_request_geometry(_view: WlcView, _geometry: &Geometry) {
}

pub extern fn pointer_button(view: WlcView, _time: u32,
                         mods: &KeyboardModifiers, button: u32,
                             state: ButtonState, point: &Point) -> bool {
    if state == ButtonState::Pressed {
        if button == LEFT_CLICK && !view.is_root() {
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).unwrap_or_else(|_| {
                    // still focus on view, even if not in tree.
                    view.focus();
                });
                if mods.mods.contains(MOD_CTRL) {
                    let action = Action {
                        view: view,
                        grab: *point,
                        edges: ResizeEdge::empty()
                    };
                    set_performing_action(Some(action));
                }
            }
        } else if button == RIGHT_CLICK && !view.is_root() {
            if let Ok(mut tree) = try_lock_tree() {
                tree.set_active_view(view).ok();
            }
            // TODO Make this set in the config file and read here.
            if mods.mods.contains(MOD_CTRL) {
                let action = Action {
                    view: view,
                    grab: *point,
                    edges: ResizeEdge::empty()
                };
                set_performing_action(Some(action));
                let geometry = view.get_geometry()
                    .expect("Could not get geometry of the view");
                let halfw = geometry.origin.x + geometry.size.w as i32 / 2;
                let halfh = geometry.origin.y + geometry.size.h as i32 / 2;

                {
                    let mut action: Action = try_lock_action().ok().and_then(|guard| *guard)
                        .unwrap_or(Action {
                            view: view,
                            grab: *point,
                            edges: ResizeEdge::empty()
                        });
                    let flag_x = if point.x < halfw {
                        RESIZE_LEFT
                    } else if point.x > halfw {
                        RESIZE_RIGHT
                    } else {
                        ResizeEdge::empty()
                    };

                    let flag_y = if point.y < halfh {
                        RESIZE_TOP
                    } else if point.y > halfh {
                        RESIZE_BOTTOM
                    } else {
                        ResizeEdge::empty()
                    };

                    action.edges = flag_x | flag_y;
                    set_performing_action(Some(action));
                }
                view.set_state(VIEW_RESIZING, true);
                return EVENT_BLOCKED
            }
        }
    } else {
        if let Ok(lock) = try_lock_action() {
            match *lock {
                Some(action) => {
                    let view = action.view;
                    if view.get_state().contains(VIEW_RESIZING) {
                        view.set_state(VIEW_RESIZING, false);
                    }
                },
                _ => {}
            }
        }
        set_performing_action(None);
    }
    EVENT_PASS_THROUGH
}

pub extern fn pointer_scroll(_view: WlcView, _time: u32,
                         _mods_ptr: &KeyboardModifiers, _axis: ScrollAxis,
                         _heights: [f64; 2]) -> bool {
    EVENT_PASS_THROUGH
}

pub extern fn pointer_motion(view: WlcView, _time: u32, point: &Point) -> bool {
    let mut result = EVENT_PASS_THROUGH;
    let mut maybe_action = None;
    {
        if let Ok(action_lock) = try_lock_action() {
            maybe_action = action_lock.clone();
        }
    }
    match maybe_action {
        None => result = EVENT_PASS_THROUGH,
        Some(action) => {
            if action.edges.bits() != 0 {
                if let Ok(mut tree) = try_lock_tree() {
                    // TODO Change to id of _view
                    // Need to implement a map of view to uuid first though...
                    if let Some(active_id) = tree.lookup_view(view) {
                        match tree.resize_container(active_id, action.edges, *point) {
                            // Return early here to not set the pointer
                            Ok(_) => return EVENT_BLOCKED,
                            Err(err) => error!("Error: {:#?}", err)
                        }
                    }
                }
            } else {
                if let Ok(mut tree) = try_lock_tree() {
                    match tree.try_drag_active(*point) {
                        Ok(_) => result = EVENT_BLOCKED,
                        Err(TreeError::PerformingAction(_)) |
                        Err(TreeError::Movement(MovementError::NotFloating(_))) => result = EVENT_PASS_THROUGH,
                        Err(err) => {
                            error!("Error: {:#?}", err);
                            result = EVENT_PASS_THROUGH
                        }
                    }
                }
            }
        }
    }
    pointer::set_position(*point);
    result
}

pub extern fn compositor_ready() {
    info!("Preparing compositor!");
    info!("Initializing Lua...");
    lua::init();
}

pub extern fn compositor_terminating() {
    info!("Compositor terminating!");
    lua::send(lua::LuaQuery::Terminate).ok();
    if let Ok(mut tree) = try_lock_tree() {
        if tree.destroy_tree().is_err() {
            error!("Could not destroy tree");
        }
    }

}

pub fn init() {
    use rustwlc::callback;

    callback::output_created(output_created);
    callback::output_destroyed(output_destroyed);
    callback::output_focus(output_focus);
    callback::output_resolution(output_resolution);
    callback::view_created(view_created);
    callback::view_destroyed(view_destroyed);
    callback::view_focus(view_focus);
    callback::view_move_to_output(view_move_to_output);
    callback::view_request_geometry(view_request_geometry);
    callback::view_request_state(view_request_state);
    callback::view_request_move(view_request_move);
    callback::view_request_resize(view_request_resize);
    callback::keyboard_key(keyboard_key);
    callback::pointer_button(pointer_button);
    callback::pointer_scroll(pointer_scroll);
    callback::pointer_motion(pointer_motion);
    callback::compositor_ready(compositor_ready);
    callback::compositor_terminate(compositor_terminating);
    trace!("Registered wlc callbacks");
}
<|endoftext|>


<commit_before>//! Callback methods for rustwlc
use rustwlc::handle::{WlcOutput, WlcView};
use rustwlc::types::*;
use rustwlc::input::{pointer, keyboard};
use rustwlc::xkb::Keysym;

use super::keys;
use super::lua;
use super::keys::{KeyEvent, KeyPress};

/// If the event is handled by way-cooler
const EVENT_HANDLED: bool = true;

/// If the event should be passed through to clients
const EVENT_PASS_THROUGH: bool = false;

// wlc callbacks

pub extern fn output_created(output: WlcOutput) -> bool {
    trace!("output_created: {:?}: {}", output, output.get_name());
    return true;
}

pub extern fn output_destroyed(output: WlcOutput) {
    trace!("output_destroyed: {:?}", output);
}

pub extern fn output_focus(output: WlcOutput, focused: bool) {
    trace!("output_focus: {:?} focus={}", output, focused);
}

pub extern fn output_resolution(output: WlcOutput,
                            old_size_ptr: &Size, new_size_ptr: &Size) {
    trace!("output_resolution: {:?} from  {:?} to {:?}",
             output, *old_size_ptr, *new_size_ptr);
}
/*
pub extern fn output_render_pre(output: WlcOutput) {
    //println!("output_render_pre");
}

pub extern fn output_render_post(output: WlcOutput) {
    //println!("output_render_post");
}
*/
pub extern fn view_created(view: WlcView) -> bool {
    trace!("view_created: {:?}: \"{}\"", view, view.get_title());
    let output = view.get_output();
    view.set_mask(output.get_mask());
    view.bring_to_front();
    view.focus();
    return true;
}

pub extern fn view_destroyed(view: WlcView) {
    trace!("view_destroyed: {:?}", view);
}

pub extern fn view_focus(current: WlcView, focused: bool) {
    trace!("view_focus: {:?} {}", current, focused);
    current.set_state(VIEW_ACTIVATED, focused);
}

pub extern fn view_move_to_output(current: WlcView,
                                  o1: WlcOutput, o2: WlcOutput) {
    trace!("view_move_to_output: {:?}, {:?}, {:?}", current, o1, o2);
}

pub extern fn view_request_geometry(view: WlcView, geometry: &Geometry) {
    trace!("view_request_geometry: {:?} wants {:?}", view, geometry);
    view.set_geometry(EDGE_NONE, geometry);
}

pub extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    trace!("view_request_state: {}, {:?}, handled: {}",
    view.get_title(), state, handled);
    view.set_state(state, handled);
}

pub extern fn view_request_move(view: WlcView, dest: &Point) {
    // Called by views when they have a dang resize mouse thing, we should only
    // let it happen in view floating mode
    trace!("view_request_move: to {}, start interactive mode.", *dest);
}

pub extern fn view_request_resize(view: WlcView,
                              edge: ResizeEdge, location: &Point) {
    trace!("view_request_resize: edge {:?}, to {}, start interactive mode.",
             edge, location);
}

pub extern fn keyboard_key(_view: WlcView, _time: u32, mods: &KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    trace!("[key] pressed, mods {:?}, key {:?}, state {:?}",
             &*mods, key, state);

    if state == KeyState::Pressed {
        // TODO this function will throw an error in Rustwlc right now
        // let mut keys = keyboard::get_current_keys().into_iter()
        //      .map(|&k| Keysym::from(k)).collect();
        let sym = keyboard::get_keysym_for_key(key, &KeyMod::empty());
        info!("[key] Found sym named {}", sym.get_name().unwrap());
        let mut keys = vec![sym];

        let press = KeyPress::new(mods.mods, keys);
        info!("[key] Created Keypress {:?}", press);

        if let Some(action) = keys::get(&press) {
            info!("[key] Found a key!");
            action();
            return EVENT_HANDLED;
        }
        else {
            info!("[key] No keypresses found.");
        }
    }

    return EVENT_PASS_THROUGH;
}

pub extern fn pointer_button(view: WlcView, button: u32,
                         mods_ptr: &KeyboardModifiers, key: u32,
                         state: ButtonState, point_ptr: &Point) -> bool {
    trace!("pointer_button: pressed {} at {}", key, *point_ptr);
    if state == ButtonState::Pressed && !view.is_root() {
        view.focus();
    }
    false
}

pub extern fn pointer_scroll(_view: WlcView, button: u32,
                         _mods_ptr: &KeyboardModifiers, axis: ScrollAxis,
                         heights: [u64; 2]) -> bool {
    trace!("pointer_scroll: press {}, {:?} to {:?}", button, axis, heights);
    false
}

pub extern fn pointer_motion(_view: WlcView, _time: u32, point: &Point) -> bool {
    pointer::set_position(point);
    false
}

/*
pub extern fn touch(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
               touch: TouchType, key: i32, point_ptr: &Point) -> bool {
    false
}
*/

pub extern fn compositor_ready() {
    info!("Preparing compositor!");
    trace!("compositor_ready");
    info!("Initializing lua...");
    lua::init();
}
<commit_msg>Improved trace logs in callbacks<commit_after>//! Callback methods for rustwlc
use rustwlc::handle::{WlcOutput, WlcView};
use rustwlc::types::*;
use rustwlc::input::{pointer, keyboard};
use rustwlc::xkb::Keysym;

use super::keys;
use super::lua;
use super::keys::{KeyEvent, KeyPress};

/// If the event is handled by way-cooler
const EVENT_HANDLED: bool = true;

/// If the event should be passed through to clients
const EVENT_PASS_THROUGH: bool = false;

// wlc callbacks

pub extern fn output_created(output: WlcOutput) -> bool {
    trace!("output_created: {:?}: {}", output, output.get_name());
    return true;
}

pub extern fn output_destroyed(output: WlcOutput) {
    trace!("output_destroyed: {:?}", output);
}

pub extern fn output_focus(output: WlcOutput, focused: bool) {
    trace!("output_focus: {:?} focus={}", output, focused);
}

pub extern fn output_resolution(output: WlcOutput,
                            old_size_ptr: &Size, new_size_ptr: &Size) {
    trace!("output_resolution: {:?} from  {:?} to {:?}",
             output, *old_size_ptr, *new_size_ptr);
}
/*
pub extern fn output_render_pre(output: WlcOutput) {
    //println!("output_render_pre");
}

pub extern fn output_render_post(output: WlcOutput) {
    //println!("output_render_post");
}
*/
pub extern fn view_created(view: WlcView) -> bool {
    trace!("view_created: {:?}: \"{}\"", view, view.get_title());
    let output = view.get_output();
    view.set_mask(output.get_mask());
    view.bring_to_front();
    view.focus();
    return true;
}

pub extern fn view_destroyed(view: WlcView) {
    trace!("view_destroyed: {:?}", view);
}

pub extern fn view_focus(current: WlcView, focused: bool) {
    trace!("view_focus: {:?} {}", current, focused);
    current.set_state(VIEW_ACTIVATED, focused);
}

pub extern fn view_move_to_output(current: WlcView,
                                  o1: WlcOutput, o2: WlcOutput) {
    trace!("view_move_to_output: {:?}, {:?}, {:?}", current, o1, o2);
}

pub extern fn view_request_geometry(view: WlcView, geometry: &Geometry) {
    trace!("view_request_geometry: {:?} wants {:?}", view, geometry);
    view.set_geometry(EDGE_NONE, geometry);
}

pub extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    trace!("view_request_state: {}, {:?}, handled: {}",
    view.get_title(), state, handled);
    view.set_state(state, handled);
}

pub extern fn view_request_move(view: WlcView, dest: &Point) {
    // Called by views when they have a dang resize mouse thing, we should only
    // let it happen in view floating mode
    trace!("view_request_move: to {}, start interactive mode.", *dest);
}

pub extern fn view_request_resize(view: WlcView,
                              edge: ResizeEdge, location: &Point) {
    trace!("view_request_resize: edge {:?}, to {}, start interactive mode.",
             edge, location);
}

pub extern fn keyboard_key(_view: WlcView, _time: u32, mods: &KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    if state == KeyState::Pressed {
        // TODO this function will throw an error in Rustwlc right now
        // let mut keys = keyboard::get_current_keys().into_iter()
        //      .map(|&k| Keysym::from(k)).collect();
        let sym = keyboard::get_keysym_for_key(key, &KeyMod::empty());
        let mut keys = vec![sym];

        let press = KeyPress::new(mods.mods, keys);
        trace!("keypress: {:?}", press);

        if let Some(action) = keys::get(&press) {
            info!("[key] Found a key!");
            action();
            return EVENT_HANDLED;
        }
        else {
            trace!("keypress: No callback");
        }
    }

    return EVENT_PASS_THROUGH;
}

pub extern fn pointer_button(view: WlcView, _time: u32,
                         mods: &KeyboardModifiers, button: u32,
                         state: ButtonState, point: &Point) -> bool {
    if state == ButtonState::Pressed {
        trace!("button: 0x{:x}, point {}", &button, point);

        if !view.is_root() {
            view.focus();
        }

        if button == 0xfee9 {
            trace!("Found left click?");
        }

        //let sym = keyboard::get_keysym_for_key(key, &KeyMod::empty());
        let sym = Keysym::from(button);
        let press = KeyPress::new(mods.mods, vec![sym.clone()]);
        trace!("sym: {} {:?}", &sym.get_name().unwrap(), press);
    }
    false
}

pub extern fn pointer_scroll(_view: WlcView, button: u32,
                         _mods_ptr: &KeyboardModifiers, axis: ScrollAxis,
                         heights: [u64; 2]) -> bool {
    trace!("pointer_scroll: press {}, {:?} to {:?}", button, axis, heights);
    false
}

pub extern fn pointer_motion(_view: WlcView, _time: u32, point: &Point) -> bool {
    pointer::set_position(point);
    false
}

/*
pub extern fn touch(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
               touch: TouchType, key: i32, point_ptr: &Point) -> bool {
    false
}
*/

pub extern fn compositor_ready() {
    info!("Preparing compositor!");
    trace!("compositor_ready");
    info!("Initializing lua...");
    lua::init();
}
<|endoftext|>


<commit_before>//! Loaders for osci memory images.
pub mod rawloader;
pub mod hexloader;

use std::{error, fmt, io, num, result};
use std::string::String;

#[derive(Debug)]
pub enum LoadError {
    None,
    IoErr(io::Error),
    ParseIntErr(num::ParseIntError),
    FormatErr(fmt::Error),
    Message(String),
}

impl LoadError {
    pub fn new() -> LoadError {
        LoadError::None
    }

    pub fn from_message(msg: String) -> LoadError {
        LoadError::Message(msg)
    }
}

impl fmt::Display for LoadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Loading failed")
    }
}

impl error::Error for LoadError {
    fn description(&self) -> &str {
        match self {
            &LoadError::None => &"Loading failed",
            &LoadError::Message(ref str) => str,
            &LoadError::IoErr(ref err) => err.description(),
            &LoadError::ParseIntErr(ref err) => err.description(),
            &LoadError::FormatErr(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &LoadError::IoErr(ref err) => Some(err),
            &LoadError::ParseIntErr(ref err) => Some(err),
            &LoadError::FormatErr(ref err) => Some(err),
            _ => None,
        }
    }
}

impl From<io::Error> for LoadError {
    fn from(err: io::Error) -> Self {
        LoadError::IoErr(err)
    }
}

impl From<num::ParseIntError> for LoadError {
    fn from(err: num::ParseIntError) -> Self {
        LoadError::ParseIntErr(err)
    }
}

impl From<fmt::Error> for LoadError {
    fn from(err: fmt::Error) -> Self {
        LoadError::FormatErr(err)
    }
}

pub type Result<T> = result::Result<T, LoadError>;
<commit_msg>docs(loader): Update documentation<commit_after>//! Loaders for osci memory images.
pub mod rawloader;
pub mod hexloader;

use std::{error, fmt, io, num, result};
use std::string::String;

#[derive(Debug)]
/// Error type for all loaders.
///
/// `LoadError` is just a union-type over a couple of built-in errors with the `From` trait implemented for each of them. This makes implementing loaders more convenient due to the `try!` macro and the `?` operator.
pub enum LoadError {
    None,
    IoErr(io::Error),
    ParseIntErr(num::ParseIntError),
    FormatErr(fmt::Error),
    Message(String),
}

// TODO: Remove None?!!

impl LoadError {
    pub fn new() -> LoadError {
        LoadError::None
    }

    pub fn from_message(msg: String) -> LoadError {
        LoadError::Message(msg)
    }
}

impl fmt::Display for LoadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Loading failed")
    }
}

impl error::Error for LoadError {
    fn description(&self) -> &str {
        match self {
            &LoadError::None => &"Loading failed",
            &LoadError::Message(ref str) => str,
            &LoadError::IoErr(ref err) => err.description(),
            &LoadError::ParseIntErr(ref err) => err.description(),
            &LoadError::FormatErr(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &LoadError::IoErr(ref err) => Some(err),
            &LoadError::ParseIntErr(ref err) => Some(err),
            &LoadError::FormatErr(ref err) => Some(err),
            _ => None,
        }
    }
}

impl From<io::Error> for LoadError {
    fn from(err: io::Error) -> Self {
        LoadError::IoErr(err)
    }
}

impl From<num::ParseIntError> for LoadError {
    fn from(err: num::ParseIntError) -> Self {
        LoadError::ParseIntErr(err)
    }
}

impl From<fmt::Error> for LoadError {
    fn from(err: fmt::Error) -> Self {
        LoadError::FormatErr(err)
    }
}

pub type Result<T> = result::Result<T, LoadError>;
<|endoftext|>


<commit_before>use std::collections::hashmap::HashMap;
use std::io::Writer;
use common::{ LogEntry };

pub struct LogWriter<'a> {
    writer: &'a mut Writer+'a,
    options: LogWriterOptions<'a>
}

pub struct LogWriterOptions<'a> {
    pub repository_link: String,
    //pub writer: &'a mut Writer+'a
}

impl<'a> LogWriter<'a> {

    fn get_commit_link (repository: &String, hash: &String) -> String {
        let short_hash = hash.as_slice().slice_chars(0,8);
        if repository.len() > 0 {
            format!("[{}]({}/commit/{})", short_hash, repository, hash)
        }
        else {
            format!("({})", short_hash)
        }
    }

    pub fn write_section (&mut self, title: &str, section: &HashMap<String, Vec<LogEntry>>) {

        if section.len() == 0 {
            return;
        }

        self.writer.write_line(format!("\n#### {}\n\n", title).as_slice());

        section.iter().all(|(component, entries)| {
            let mut prefix:String;
            let nested = entries.len() > 1;

            //TODO: implement the empty component stuff
            if nested {
                self.writer.write(format!("* **{}**\n", component).as_bytes());
                prefix = "  *".to_string();
            }
            else {
                prefix = format!("* **{}**", component)
            }

            entries.iter().all(|entry| {
                self.writer.write(format!("{} {} ({}", prefix, entry.subject, LogWriter::get_commit_link(&self.options.repository_link, &entry.hash)).as_bytes());
                //TODO: implement closes stuff

                self.writer.write(")\n".as_bytes());

                true
            });
            true
        });
    }

    pub fn new<T:Writer + Send>(writer: &'a mut T, options: LogWriterOptions) -> LogWriter<'a> {
        LogWriter {
            writer: writer,
            options: options
        }
    }
}<commit_msg>chore(LogWriter): remove commented code<commit_after>use std::collections::hashmap::HashMap;
use std::io::Writer;
use common::{ LogEntry };

pub struct LogWriter<'a> {
    writer: &'a mut Writer+'a,
    options: LogWriterOptions<'a>
}

pub struct LogWriterOptions<'a> {
    pub repository_link: String
}

impl<'a> LogWriter<'a> {

    fn get_commit_link (repository: &String, hash: &String) -> String {
        let short_hash = hash.as_slice().slice_chars(0,8);
        if repository.len() > 0 {
            format!("[{}]({}/commit/{})", short_hash, repository, hash)
        }
        else {
            format!("({})", short_hash)
        }
    }

    pub fn write_section (&mut self, title: &str, section: &HashMap<String, Vec<LogEntry>>) {

        if section.len() == 0 {
            return;
        }

        self.writer.write_line(format!("\n#### {}\n\n", title).as_slice());

        section.iter().all(|(component, entries)| {
            let mut prefix:String;
            let nested = entries.len() > 1;

            //TODO: implement the empty component stuff
            if nested {
                self.writer.write(format!("* **{}**\n", component).as_bytes());
                prefix = "  *".to_string();
            }
            else {
                prefix = format!("* **{}**", component)
            }

            entries.iter().all(|entry| {
                self.writer.write(format!("{} {} ({}", prefix, entry.subject, LogWriter::get_commit_link(&self.options.repository_link, &entry.hash)).as_bytes());
                //TODO: implement closes stuff

                self.writer.write(")\n".as_bytes());

                true
            });
            true
        });
    }

    pub fn new<T:Writer + Send>(writer: &'a mut T, options: LogWriterOptions) -> LogWriter<'a> {
        LogWriter {
            writer: writer,
            options: options
        }
    }
}<|endoftext|>


<commit_before>//! Code for the internal Lua thread which handles all Lua requests.

use std::thread;
use std::fs::{File};
use std::path::Path;
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

use hlua::{Lua, LuaError, functions_read};

use super::types::*;
use super::rust_interop;
use super::init_path;

lazy_static! {
    /// Sends requests to the Lua thread
    static ref SENDER: Mutex<Option<Sender<LuaMessage>>> = Mutex::new(None);

    /// Whether the Lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

pub const ERR_LOCK_RUNNING: &'static str = "Lua thread: unable to lock RUNNING";
pub const ERR_LOCK_SENDER: &'static str = "Lua thread: unable to lock SENDER";

const INIT_LUA_FUNC: &'static str = "way_cooler_init";

/// Struct sent to the Lua query
struct LuaMessage {
    reply: Sender<LuaResponse>,
    query: LuaQuery
}

unsafe impl Send for LuaMessage { }
unsafe impl Sync for LuaMessage { }

impl Debug for LuaMessage {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "LuaMessage({:?})", self.query)
    }
}

// Reexported in lua/mod.rs:11
/// Whether the Lua thread is currently available.
pub fn running() -> bool {
    *RUNNING.read().expect(ERR_LOCK_RUNNING)
}

// Reexported in lua/mod.rs:11
/// Errors which may arise from attempting
/// to sending a message to the Lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked.
    /// Following the `Sender` API, the original value sent is returned.
    Sender(LuaQuery)
}

// Reexported in lua/mod.rs:11
/// Attemps to send a LuaQuery to the Lua thread.
pub fn send(query: LuaQuery) -> Result<Receiver<LuaResponse>, LuaSendError> {
    if !running() {
        return Err(LuaSendError::ThreadClosed);
    }
    let thread_sender: Sender<LuaMessage>;
    {
        let maybe_sender = SENDER.lock().expect(ERR_LOCK_SENDER);
        match *maybe_sender {
            Some(ref real_sender) => {
                // Senders are designed to be cloneable
                thread_sender = real_sender.clone();
            },
            // If the sender doesn't exist yet, the thread doesn't either
            None => {
                return Err(LuaSendError::ThreadUninitialized);
            }
        }
    }
    // Create a response channel
    let (response_tx, response_rx) = channel();
    let message = LuaMessage { reply: response_tx, query: query };
    match thread_sender.send(message) {
        Ok(_) => Ok(response_rx),
        Err(e) => Err(LuaSendError::Sender(e.0.query))
    }
}

/// Initialize the Lua thread.
pub fn init() {
    debug!("Initializing...");
    let (tx, receiver) = channel();
    *SENDER.lock().expect(ERR_LOCK_SENDER) = Some(tx);
    let mut lua = Lua::new();
    debug!("Loading Lua libraries...");
    lua.openlibs();
    debug!("Loading way-cooler libraries...");
    rust_interop::register_libraries(&mut lua);

    let (use_config, maybe_init_file) = init_path::get_config();
    if use_config {
        match maybe_init_file {
            Ok(init_file) => {
                let _: () = lua.execute_from_reader(init_file)
                    .expect("Unable to load init file");
                debug!("Read init.lua successfully");
            }
            Err(reason) => {
                panic!("Unable to load init file: {}", reason)
            }
        }
    }
    else {
        info!("Skipping config search");
    }

    // Call the special init hook function that we read from the init file
    lua.get(INIT_LUA_FUNC)
        .map(|mut f: functions_read::LuaFunction<_>|  f.call().unwrap_or_else(|err| {
            error!("Lua function \"{}\" returned an error: {:?}", INIT_LUA_FUNC, err);
        }));

    // Only ready after loading libs
    *RUNNING.write().expect(ERR_LOCK_RUNNING) = true;
    debug!("Entering main loop...");
    let _lua_handle = thread::Builder::new()
        .name("Lua thread".to_string())
        .spawn(move || { main_loop(receiver, &mut lua) });
}

/// Main loop of the Lua thread:
///
/// ## Loop
/// * Wait for a message from the receiver
/// * Handle message
/// * Send response
fn main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        trace!("Lua: awaiting request");
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                if !handle_message(message, lua) {
                    return
                }
            }
        }
    }
}

/// Handle each LuaQuery option sent to the thread
fn handle_message(request: LuaMessage, lua: &mut Lua) -> bool {
    match request.query {
        LuaQuery::Terminate => {
            trace!("Received terminate signal");
            if let Err(error) = lua.execute::<()>("way_cooler.handle_termination") {
                error!("Lua termination callback returned an error: {:?}", error);
            }
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            info!("Lua thread terminating!");
            return false
        },
        LuaQuery::Restart => {
            trace!("Received restart signal!");
            if let Err(error) = lua.execute::<()>("way_cooler.hanle_termination") {
                error!("Lua restart callback returned an error: {:?}", error);
            }
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            // The only real way to restart
            let _new_handle = thread::Builder::new()
                .name("Lua re-init".to_string())
                .spawn(move || {
                    init();
                });

            info!("Lua thread restarting");
            return false
        },
        LuaQuery::Execute(code) => {
            trace!("Received request to execute {}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error executing code: {:?}", error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Code executed okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        },
        LuaQuery::ExecFile(name) => {
            info!("Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("Error executing {}!", name);
                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("Execution of {} successful.", name);
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let Ok
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());
                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },
        LuaQuery::ExecRust(func) => {
            let result = func(lua);
            thread_send(request.reply, LuaResponse::Variable(Some(result)));
        },
        LuaQuery::HandleKey(press) => {
            trace!("Lua: handling keypress {}", &press);
            let press_ix = press.get_lua_index_string();
            // Access the index
            let code = format!("__key_map['{}']()", press_ix);
            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error handling {}: {:?}", &press, error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Handled keypress okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        }
        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
    }
    return true
}

fn thread_send(sender: Sender<LuaResponse>, response: LuaResponse) {
    match sender.send(response) {
        Err(err) => {
            match err.0 {
                LuaResponse::Pong => {}, // Those are boring
                _ => {
                    warn!("thread: Someone dropped an important Lua response!");
                }
            }
        }
        Ok(_) => {}
    }
}
<commit_msg>Use constants to prevent typos<commit_after>//! Code for the internal Lua thread which handles all Lua requests.

use std::thread;
use std::fs::{File};
use std::path::Path;
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

use hlua::{Lua, LuaError, functions_read};

use super::types::*;
use super::rust_interop;
use super::init_path;

lazy_static! {
    /// Sends requests to the Lua thread
    static ref SENDER: Mutex<Option<Sender<LuaMessage>>> = Mutex::new(None);

    /// Whether the Lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

pub const ERR_LOCK_RUNNING: &'static str = "Lua thread: unable to lock RUNNING";
pub const ERR_LOCK_SENDER: &'static str = "Lua thread: unable to lock SENDER";

const INIT_LUA_FUNC: &'static str = "way_cooler_init";
const LUA_TERMINATE_CODE: &'static str = "way_cooler.handle_termination()";
const LUA_RESTART_CODE: &'static str = "way_cooler.handle_restart()";

/// Struct sent to the Lua query
struct LuaMessage {
    reply: Sender<LuaResponse>,
    query: LuaQuery
}

unsafe impl Send for LuaMessage { }
unsafe impl Sync for LuaMessage { }

impl Debug for LuaMessage {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "LuaMessage({:?})", self.query)
    }
}

// Reexported in lua/mod.rs:11
/// Whether the Lua thread is currently available.
pub fn running() -> bool {
    *RUNNING.read().expect(ERR_LOCK_RUNNING)
}

// Reexported in lua/mod.rs:11
/// Errors which may arise from attempting
/// to sending a message to the Lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked.
    /// Following the `Sender` API, the original value sent is returned.
    Sender(LuaQuery)
}

// Reexported in lua/mod.rs:11
/// Attemps to send a LuaQuery to the Lua thread.
pub fn send(query: LuaQuery) -> Result<Receiver<LuaResponse>, LuaSendError> {
    if !running() {
        return Err(LuaSendError::ThreadClosed);
    }
    let thread_sender: Sender<LuaMessage>;
    {
        let maybe_sender = SENDER.lock().expect(ERR_LOCK_SENDER);
        match *maybe_sender {
            Some(ref real_sender) => {
                // Senders are designed to be cloneable
                thread_sender = real_sender.clone();
            },
            // If the sender doesn't exist yet, the thread doesn't either
            None => {
                return Err(LuaSendError::ThreadUninitialized);
            }
        }
    }
    // Create a response channel
    let (response_tx, response_rx) = channel();
    let message = LuaMessage { reply: response_tx, query: query };
    match thread_sender.send(message) {
        Ok(_) => Ok(response_rx),
        Err(e) => Err(LuaSendError::Sender(e.0.query))
    }
}

/// Initialize the Lua thread.
pub fn init() {
    debug!("Initializing...");
    let (tx, receiver) = channel();
    *SENDER.lock().expect(ERR_LOCK_SENDER) = Some(tx);
    let mut lua = Lua::new();
    debug!("Loading Lua libraries...");
    lua.openlibs();
    debug!("Loading way-cooler libraries...");
    rust_interop::register_libraries(&mut lua);

    let (use_config, maybe_init_file) = init_path::get_config();
    if use_config {
        match maybe_init_file {
            Ok(init_file) => {
                let _: () = lua.execute_from_reader(init_file)
                    .expect("Unable to load init file");
                debug!("Read init.lua successfully");
            }
            Err(reason) => {
                panic!("Unable to load init file: {}", reason)
            }
        }
    }
    else {
        info!("Skipping config search");
    }

    // Call the special init hook function that we read from the init file
    lua.get(INIT_LUA_FUNC)
        .map(|mut f: functions_read::LuaFunction<_>|  f.call().unwrap_or_else(|err| {
            error!("Lua function \"{}\" returned an error: {:?}", INIT_LUA_FUNC, err);
        }));

    // Only ready after loading libs
    *RUNNING.write().expect(ERR_LOCK_RUNNING) = true;
    debug!("Entering main loop...");
    let _lua_handle = thread::Builder::new()
        .name("Lua thread".to_string())
        .spawn(move || { main_loop(receiver, &mut lua) });
}

/// Main loop of the Lua thread:
///
/// ## Loop
/// * Wait for a message from the receiver
/// * Handle message
/// * Send response
fn main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        trace!("Lua: awaiting request");
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                if !handle_message(message, lua) {
                    return
                }
            }
        }
    }
}

/// Handle each LuaQuery option sent to the thread
fn handle_message(request: LuaMessage, lua: &mut Lua) -> bool {
    match request.query {
        LuaQuery::Terminate => {
            trace!("Received terminate signal");
            if let Err(error) = lua.execute::<()>(LUA_TERMINATE_CODE) {
                error!("Lua termination callback returned an error: {:?}", error);
            }
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            info!("Lua thread terminating!");
            return false
        },
        LuaQuery::Restart => {
            trace!("Received restart signal!");
            if let Err(error) = lua.execute::<()>(LUA_RESTART_CODE) {
                error!("Lua restart callback returned an error: {:?}", error);
            }
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            // The only real way to restart
            let _new_handle = thread::Builder::new()
                .name("Lua re-init".to_string())
                .spawn(move || {
                    init();
                });

            info!("Lua thread restarting");
            return false
        },
        LuaQuery::Execute(code) => {
            trace!("Received request to execute {}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error executing code: {:?}", error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Code executed okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        },
        LuaQuery::ExecFile(name) => {
            info!("Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("Error executing {}!", name);
                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("Execution of {} successful.", name);
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let Ok
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());
                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },
        LuaQuery::ExecRust(func) => {
            let result = func(lua);
            thread_send(request.reply, LuaResponse::Variable(Some(result)));
        },
        LuaQuery::HandleKey(press) => {
            trace!("Lua: handling keypress {}", &press);
            let press_ix = press.get_lua_index_string();
            // Access the index
            let code = format!("__key_map['{}']()", press_ix);
            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error handling {}: {:?}", &press, error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Handled keypress okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        }
        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
    }
    return true
}

fn thread_send(sender: Sender<LuaResponse>, response: LuaResponse) {
    match sender.send(response) {
        Err(err) => {
            match err.0 {
                LuaResponse::Pong => {}, // Those are boring
                _ => {
                    warn!("thread: Someone dropped an important Lua response!");
                }
            }
        }
        Ok(_) => {}
    }
}
<|endoftext|>


<commit_before>use { CopyReadable, ConsumeReadable, LoadedVariable, Pushable };
use liblua;

pub struct LuaTable<'a> {
    variable: LoadedVariable<'a>
}

// while the LuaTableIterator is active, the current key is constantly pushed over the table
pub struct LuaTableIterator<'a, 'b> {
    table: &'b mut LuaTable<'a>
}

impl<'a> ConsumeReadable<'a> for LuaTable<'a> {
    fn read_from_variable(var: LoadedVariable<'a>)
        -> Result<LuaTable<'a>, LoadedVariable<'a>>
    {
        if unsafe { liblua::lua_istable(var.lua.lua, -1) } {
            Ok(LuaTable{ variable: var })
        } else {
            Err(var)
        }
    }
}

impl<'a> LuaTable<'a> {
    pub fn iter<'b>(&'b mut self)
        -> LuaTableIterator<'a, 'b>
    {
        ().push_to_lua(self.variable.lua);
        LuaTableIterator { table: self }
    }
}

impl<'a, 'b, K: CopyReadable, V: CopyReadable> Iterator<Option<(K,V)>> for LuaTableIterator<'a, 'b> {
    fn next(&mut self)
        -> Option<Option<(K,V)>>
    {
        // this call pushes the next key and value on the stack
        if unsafe { liblua::lua_next(self.table.variable.lua.lua, -2) } == 0 {
            return None
        }

        let key = CopyReadable::read_from_lua(self.table.variable.lua, -2);
        let value = CopyReadable::read_from_lua(self.table.variable.lua, -1);

        // removing the value, leaving only the key on the top of the stack
        unsafe { liblua::lua_pop(self.table.variable.lua.lua, 1) };

        //
        if key.is_none() || value.is_none() {
            Some(None)
        } else {
            Some(Some((key.unwrap(), value.unwrap())))
        }
    }
}

// TODO: this destructor crashes the compiler
/*impl<'a, 'b> Drop for LuaTableIterator<'a, 'b> {
    fn drop(&mut self) {
        unsafe { liblua::lua_pop(self.table.variable.lua.lua, 1) }
    }
}*/

#[cfg(test)]
mod tests {
    use Lua;
    use lua_tables::LuaTable;

    #[test]
    fn iterable() {
        let mut lua = Lua::new();

        let _: () = lua.execute("a = { 9, 8, 7 }").unwrap();

        let mut table: LuaTable = lua.get("a").unwrap();

        let tableContent: Vec<Option<(uint, uint)>> = table.iter().collect();

        assert_eq!(tableContent, vec!( Some((1,9)), Some((2,8)), Some((3,7)) ));
    }
}
<commit_msg>Add test for iterating the same table multiple times<commit_after>use { CopyReadable, ConsumeReadable, LoadedVariable, Pushable };
use liblua;

pub struct LuaTable<'a> {
    variable: LoadedVariable<'a>
}

// while the LuaTableIterator is active, the current key is constantly pushed over the table
pub struct LuaTableIterator<'a, 'b> {
    table: &'b mut LuaTable<'a>
}

impl<'a> ConsumeReadable<'a> for LuaTable<'a> {
    fn read_from_variable(var: LoadedVariable<'a>)
        -> Result<LuaTable<'a>, LoadedVariable<'a>>
    {
        if unsafe { liblua::lua_istable(var.lua.lua, -1) } {
            Ok(LuaTable{ variable: var })
        } else {
            Err(var)
        }
    }
}

impl<'a> LuaTable<'a> {
    pub fn iter<'b>(&'b mut self)
        -> LuaTableIterator<'a, 'b>
    {
        ().push_to_lua(self.variable.lua);
        LuaTableIterator { table: self }
    }
}

impl<'a, 'b, K: CopyReadable, V: CopyReadable> Iterator<Option<(K,V)>> for LuaTableIterator<'a, 'b> {
    fn next(&mut self)
        -> Option<Option<(K,V)>>
    {
        // this call pushes the next key and value on the stack
        if unsafe { liblua::lua_next(self.table.variable.lua.lua, -2) } == 0 {
            return None
        }

        let key = CopyReadable::read_from_lua(self.table.variable.lua, -2);
        let value = CopyReadable::read_from_lua(self.table.variable.lua, -1);

        // removing the value, leaving only the key on the top of the stack
        unsafe { liblua::lua_pop(self.table.variable.lua.lua, 1) };

        //
        if key.is_none() || value.is_none() {
            Some(None)
        } else {
            Some(Some((key.unwrap(), value.unwrap())))
        }
    }
}

// TODO: this destructor crashes the compiler
/*impl<'a, 'b> Drop for LuaTableIterator<'a, 'b> {
    fn drop(&mut self) {
        unsafe { liblua::lua_pop(self.table.variable.lua.lua, 1) }
    }
}*/

#[cfg(test)]
mod tests {
    use Lua;
    use lua_tables::LuaTable;

    #[test]
    fn iterable() {
        let mut lua = Lua::new();

        let _: () = lua.execute("a = { 9, 8, 7 }").unwrap();

        let mut table: LuaTable = lua.get("a").unwrap();
        let mut counter = 0u;

        for (key, value) in table.iter().filter_map(|e| e) {
            let k: uint = key;
            let v: uint = value;
            assert_eq!(key + value, 10);
            counter += 1;
        }

        assert_eq!(counter, 3);
    }

    #[test]
    fn iterable_multipletimes() {
        let mut lua = Lua::new();

        let _: () = lua.execute("a = { 9, 8, 7 }").unwrap();

        let mut table: LuaTable = lua.get("a").unwrap();

        for _ in range(0u, 10) {
            let tableContent: Vec<Option<(uint, uint)>> = table.iter().collect();
            assert_eq!(tableContent, vec!( Some((1,9)), Some((2,8)), Some((3,7)) ));
        }
    }
}
<|endoftext|>