<commit_before>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError, LuaTable, PushGuard};
use hlua::any::AnyLuaValue;

use rustc_serialize::json::Json;

use std::collections::BTreeMap;

use std::thread;
use std::fs::{File};
use std::path::Path;
use std::io::Write;

use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::borrow::Borrow;

use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

#[macro_use]
mod funcs;
#[cfg(test)]
mod tests;

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);
}

/// Represents an identifier for dealing with nested tables.
///
/// To access foo.bar.baz, use vec!["foo", "bar", "baz"].
///
/// To access foo[2], use vec!["foo", 2].
pub type LuaIdent = Vec<String>;

/// Messages sent to the lua thread
#[derive(Debug)]
pub enum LuaQuery {
    /// Pings the lua thread
    Ping,
    /// Halt the lua thread
    Terminate,
    // Restart the lua thread
    Restart,

    /// Execute a string
    Execute(String),
    /// Execute a file
    ExecFile(String),

    /// Get a variable, expecting an AnyLuaValue
    GetValue(LuaIdent),
    /// Invoke a function found at the position,
    /// with the specified arguments.
    Invoke(LuaIdent, Vec<AnyLuaValue>),
    /// Set a value
    SetValue(LuaIdent, Json),
    /// Create a new table
    NewTable(LuaIdent),
}

/// Messages received from lua thread
pub enum LuaResponse {
    /// If the identifier had length 0
    InvalidName,
    /// Lua variable obtained
    Variable(Option<AnyLuaValue>),
    /// Lua error
    Error(hlua::LuaError),
    /// A function is returned
    Function(hlua::functions_read::LuaFunction<String>),
    /// Pong response from lua ping
    Pong,
}

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

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

impl Debug for LuaResponse {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            LuaResponse::InvalidName =>
                write!(f, "LuaReponse::InvalidName"),
            LuaResponse::Variable(ref var) =>
                write!(f, "LuaResponse::Variable({:?})", var),
            LuaResponse::Error(ref err) =>
                write!(f, "LuaResponse::Error({:?})", err),
            LuaResponse::Function(_) =>
                write!(f, "LuaResponse::Function"),
            LuaResponse::Pong =>
                write!(f, "LuaResponse::Pong")
        }
    }
}

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

/// Whether the lua thread is currently available
pub fn thread_running() -> bool {
    *RUNNING.read().unwrap()
}

/// 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)
}

/// Attemps to send a LuaQuery to the lua thread.
pub fn send(query: LuaQuery) -> Result<Receiver<LuaResponse>,LuaSendError> {
    if !thread_running() {
        Err(LuaSendError::ThreadClosed)
    }
    else if let Some(sender) = SENDER.lock().unwrap().clone() {
        let (tx, rx) = channel();
        let message = LuaMessage { reply: tx, query: query };
        match sender.send(message) {
            Ok(_) => Ok(rx),
            Err(e) => Err(LuaSendError::Sender(e.0.query))
        }
    }
    else {
        Err(LuaSendError::ThreadUninitialized)
    }
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaMessage>();
    {
        let mut sender = SENDER.lock().unwrap();
        *sender = Some(query_tx);
    }

    thread::spawn(move || {
        thread_init(query_rx);
    });
    trace!("Created thread. Init finished.");
}

fn thread_init(receiver: Receiver<LuaMessage>) {
    trace!("thread: initializing.");
    let mut lua = Lua::new();
    //unsafe {
    //    hlua_ffi::lua_atpanic(&mut lua.as_mut_lua().0, thread_on_panic);
    //}
    debug!("thread: Loading Lua libraries...");
    lua.openlibs();
    trace!("thread: Loading way-cooler lua extensions...");
    // We should have some good file handling, read files from /usr by default,
    // but for now we're reading directly from the source.
    lua.execute_from_reader::<(), File>(
        File::open("lib/lua/init.lua").unwrap()
    ).unwrap();
    trace!("thread: loading way-cooler libraries...");
    funcs::register_libraries(&mut lua);
    // Only ready after loading libs
    *RUNNING.write().unwrap() = true;
    debug!("thread: entering main loop...");
    thread_main_loop(receiver, &mut lua);
}

fn thread_main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().unwrap() = false;

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

fn thread_handle_message(request: LuaMessage, lua: &mut Lua) {
    match request.query {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");
            *RUNNING.write().unwrap() = false;

            info!("thread: Lua thread terminating!");
            thread_send(request.reply, LuaResponse::Pong);
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");
            error!("thread: Lua thread restart not supported!");

            *RUNNING.write().unwrap() = false;
            thread_send(request.reply, LuaResponse::Pong);

            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {}", code);

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

        LuaQuery::ExecFile(name) => {
            info!("thread: 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!("thread: Error executing {}!", name);

                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: 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
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetValue(varname) => {
            trace!("thread: Received request to get variable {:?}", varname);

            if varname.len() == 0 {
                thread_send(request.reply, LuaResponse::InvalidName);
                return;
            }
            // Table[0] String had to be cloned, it'd be nice if Rust let us
            // borrow out parts of memory
            match lua.get::<AnyLuaValue, _>(varname[0].clone()) {
                Some(table) => {
                    let full_table = walk_table(table, &varname[1..]);
                    thread_send(request.reply,
                                LuaResponse::Variable(full_table));
                },
                None => thread_send(request.reply, LuaResponse::Variable(None))
            }
        },

        LuaQuery::SetValue(name, val) => {
            trace!("thread: SetValue: Setting {:?} to {:?}", name, val);
            /*
            let maybe_table: Option<LuaTable<_>> = lua.get::<_, _>(name[0]);

            let table: LuaTable<_>;

            if name.len() == 0 {
                thread_send(request.reply, LuaResponse::InvalidName);
            }
            else if name.len() == 1 {
                let lua_val =
                table.set(name[0], val);
            }
            else {
                match maybe_table {
                    Some(table) => {

                    }
                }
            }*/
            unimplemented!();
        },

        LuaQuery::NewTable(name_list) => {
            panic!("thread: unimplemented LuaQuery::NewTable!");
        },

        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
        _ => {
            panic!("Unimplemented send type for lua thread!");
        }
    }
}

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(_) => {}
    }
}

fn walk_table(table: AnyLuaValue, names: &[String]) -> Option<AnyLuaValue> {
    if let Some(name) = names.first() {
        if let AnyLuaValue::LuaArray(arr) = table {
            for (key, val) in arr {
                if let AnyLuaValue::LuaString(key_str) = key {
                    if *key_str == *name {
                        return walk_table(val, &names[1..]);
                    }
                }
            }
            return None;
        }
        else {
            return None;
        }
    }
    else {
        return Some(table); // ???
    }
}

/*
fn set_value<'l>(lua: &'l mut Lua, mut table: PushGuard<LuaTable<Lua>>,
             names: &[String], val: AnyLuaValue) {
    // Should not be reached!
    if names.len() == 0 {
        return;
    }
    // The last name is the name of the value
    else if names.len() == 1 {
        table.set(names[0].clone(), val);
    }
    else {
        let maybe_table = table.get::<_, _>(names[0]);
        match maybe_table {
            Some(new_table) => {
                set_value(&mut lua, new_table, &names[1..], val);
            }
            None => { return; }
        }
    }
}*/

/// Converts a Json map into an AnyLuaValue
pub fn json_to_lua(json: Json) -> AnyLuaValue {
    match json {
        Json::String(val)  => AnyLuaValue::LuaString(val),
        Json::Boolean(val) => AnyLuaValue::LuaBoolean(val),
        Json::F64(val)     => AnyLuaValue::LuaNumber(val),
        Json::I64(val)     => AnyLuaValue::LuaNumber((val as i32) as f64),
        Json::U64(val)     => AnyLuaValue::LuaNumber((val as u32) as f64),
        Json::Null         => AnyLuaValue::LuaNil,
        Json::Array(vals)  => {
            let mut lua_arr = Vec::with_capacity(vals.len());
            for (ix, val) in vals.into_iter().enumerate() {
                lua_arr.push((AnyLuaValue::LuaNumber(ix as f64 + 1.0),
                              json_to_lua(val)));
            }
            AnyLuaValue::LuaArray(lua_arr)
        },
        Json::Object(vals) => {
            let mut lua_table = Vec::with_capacity(vals.len());
            for (key, val) in vals.into_iter() {
                lua_table.push((AnyLuaValue::LuaString(key),
                                json_to_lua(val)));
            }
            AnyLuaValue::LuaArray(lua_table)
        }
    }
}

/// Converts an `AnyLuaValue` to a `Json`.
///
/// For an already-matched `LuaArray`, use `lua_array_to_json`.
///
/// For a `LuaArray` that should be mapped to a `JsonObject`,
/// use `lua_object_to_json`.
pub fn lua_to_json(lua: AnyLuaValue) -> Result<Json, ()> {
    match lua {
        AnyLuaValue::LuaNil => Ok(Json::Null),
        AnyLuaValue::LuaString(val) => Ok(Json::String(val)),
        AnyLuaValue::LuaNumber(val) => Ok(Json::F64(val)),
        AnyLuaValue::LuaBoolean(val) => Ok(Json::Boolean(val)),
        AnyLuaValue::LuaArray(arr) => lua_array_to_json(arr),
        AnyLuaValue::LuaOther => Err(())
    }
}

pub fn lua_array_to_json(arr: Vec<(AnyLuaValue, AnyLuaValue)>)
                         -> Result<Json, ()> {
    // Check if every key is a number
    let mut counter = 0.0; // Account for first index?

    for &(ref key, ref _val) in &arr {
        match *key {
            AnyLuaValue::LuaNumber(num) => {
                counter += num;
            }
            AnyLuaValue::LuaString(_) => {
                break;
            }
            // Non-string keys are not allowed
            _ => {
                return Err(());
            }
        }
    }

    // Gauss' trick
    let desired_sum = ((arr.len()) * (arr.len() + 1)) / 2;
    if counter != desired_sum as f64 {
        return lua_object_to_json(arr);
    }

    let mut json_arr: Vec<Json> = Vec::with_capacity(arr.len());

    for (_key, val) in arr.into_iter() {
        let lua_val = try!(lua_to_json(val));
        json_arr.push(lua_val);
    }
    Ok(Json::Array(json_arr))
}

pub fn lua_object_to_json(obj: Vec<(AnyLuaValue, AnyLuaValue)>)
                          -> Result<Json, ()> {
    let mut json_obj: BTreeMap<String, Json> = BTreeMap::new();

    for (key, val) in obj.into_iter() {
        match key {
            AnyLuaValue::LuaString(text) => {
                json_obj.insert(text, try!(lua_to_json(val)));
            },
            AnyLuaValue::LuaNumber(ix) => {
                json_obj.insert(format!("{}", ix), try!(lua_to_json(val)));
            }
            _ => { return Err(()); }
        }
    }
    Ok(Json::Object(json_obj))
}
<commit_msg>lua handle_message panics on unimplemented message<commit_after>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError, LuaTable, PushGuard};
use hlua::any::AnyLuaValue;

use rustc_serialize::json::Json;

use std::collections::BTreeMap;

use std::thread;
use std::fs::{File};
use std::path::Path;
use std::io::Write;

use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::borrow::Borrow;

use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

#[macro_use]
mod funcs;
#[cfg(test)]
mod tests;

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);
}

/// Represents an identifier for dealing with nested tables.
///
/// To access foo.bar.baz, use vec!["foo", "bar", "baz"].
///
/// To access foo[2], use vec!["foo", 2].
pub type LuaIdent = Vec<String>;

/// Messages sent to the lua thread
#[derive(Debug)]
pub enum LuaQuery {
    /// Pings the lua thread
    Ping,
    /// Halt the lua thread
    Terminate,
    // Restart the lua thread
    Restart,

    /// Execute a string
    Execute(String),
    /// Execute a file
    ExecFile(String),

    /// Get a variable, expecting an AnyLuaValue
    GetValue(LuaIdent),
    /// Invoke a function found at the position,
    /// with the specified arguments.
    Invoke(LuaIdent, Vec<AnyLuaValue>),
    /// Set a value
    SetValue(LuaIdent, Json),
    /// Create a new table
    NewTable(LuaIdent),
}

/// Messages received from lua thread
pub enum LuaResponse {
    /// If the identifier had length 0
    InvalidName,
    /// Lua variable obtained
    Variable(Option<AnyLuaValue>),
    /// Lua error
    Error(hlua::LuaError),
    /// A function is returned
    Function(hlua::functions_read::LuaFunction<String>),
    /// Pong response from lua ping
    Pong,
}

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

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

impl Debug for LuaResponse {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            LuaResponse::InvalidName =>
                write!(f, "LuaReponse::InvalidName"),
            LuaResponse::Variable(ref var) =>
                write!(f, "LuaResponse::Variable({:?})", var),
            LuaResponse::Error(ref err) =>
                write!(f, "LuaResponse::Error({:?})", err),
            LuaResponse::Function(_) =>
                write!(f, "LuaResponse::Function"),
            LuaResponse::Pong =>
                write!(f, "LuaResponse::Pong")
        }
    }
}

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

/// Whether the lua thread is currently available
pub fn thread_running() -> bool {
    *RUNNING.read().unwrap()
}

/// 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)
}

/// Attemps to send a LuaQuery to the lua thread.
pub fn send(query: LuaQuery) -> Result<Receiver<LuaResponse>,LuaSendError> {
    if !thread_running() {
        Err(LuaSendError::ThreadClosed)
    }
    else if let Some(sender) = SENDER.lock().unwrap().clone() {
        let (tx, rx) = channel();
        let message = LuaMessage { reply: tx, query: query };
        match sender.send(message) {
            Ok(_) => Ok(rx),
            Err(e) => Err(LuaSendError::Sender(e.0.query))
        }
    }
    else {
        Err(LuaSendError::ThreadUninitialized)
    }
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaMessage>();
    {
        let mut sender = SENDER.lock().unwrap();
        *sender = Some(query_tx);
    }

    thread::spawn(move || {
        thread_init(query_rx);
    });
    trace!("Created thread. Init finished.");
}

fn thread_init(receiver: Receiver<LuaMessage>) {
    trace!("thread: initializing.");
    let mut lua = Lua::new();
    //unsafe {
    //    hlua_ffi::lua_atpanic(&mut lua.as_mut_lua().0, thread_on_panic);
    //}
    debug!("thread: Loading Lua libraries...");
    lua.openlibs();
    trace!("thread: Loading way-cooler lua extensions...");
    // We should have some good file handling, read files from /usr by default,
    // but for now we're reading directly from the source.
    lua.execute_from_reader::<(), File>(
        File::open("lib/lua/init.lua").unwrap()
    ).unwrap();
    trace!("thread: loading way-cooler libraries...");
    funcs::register_libraries(&mut lua);
    // Only ready after loading libs
    *RUNNING.write().unwrap() = true;
    debug!("thread: entering main loop...");
    thread_main_loop(receiver, &mut lua);
}

fn thread_main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().unwrap() = false;

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

fn thread_handle_message(request: LuaMessage, lua: &mut Lua) {
    match request.query {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");
            *RUNNING.write().unwrap() = false;

            info!("thread: Lua thread terminating!");
            thread_send(request.reply, LuaResponse::Pong);
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");
            error!("thread: Lua thread restart not supported!");

            *RUNNING.write().unwrap() = false;
            thread_send(request.reply, LuaResponse::Pong);

            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {}", code);

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

        LuaQuery::ExecFile(name) => {
            info!("thread: 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!("thread: Error executing {}!", name);

                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: 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
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetValue(varname) => {
            trace!("thread: Received request to get variable {:?}", varname);

            if varname.len() == 0 {
                thread_send(request.reply, LuaResponse::InvalidName);
                return;
            }
            // Table[0] String had to be cloned, it'd be nice if Rust let us
            // borrow out parts of memory
            match lua.get::<AnyLuaValue, _>(varname[0].clone()) {
                Some(table) => {
                    let full_table = walk_table(table, &varname[1..]);
                    thread_send(request.reply,
                                LuaResponse::Variable(full_table));
                },
                None => thread_send(request.reply, LuaResponse::Variable(None))
            }
        },

        LuaQuery::SetValue(name, val) => {
            trace!("thread: SetValue: Setting {:?} to {:?}", name, val);
            /*
            let maybe_table: Option<LuaTable<_>> = lua.get::<_, _>(name[0]);

            let table: LuaTable<_>;

            if name.len() == 0 {
                thread_send(request.reply, LuaResponse::InvalidName);
            }
            else if name.len() == 1 {
                let lua_val =
                table.set(name[0], val);
            }
            else {
                match maybe_table {
                    Some(table) =>
                }
            }*/
        },
        LuaQuery::Invoke(ident, vals) => {
            panic!("thread: unimplemented LuaQuery::Invoke!");
            /*
            if ident.len() == 0 {
                thread_send(request.reply, LuaResponse::InvalidName);
                return;
            }
            */
        },
        LuaQuery::NewTable(name_list) => {
            panic!("thread: unimplemented LuaQuery::NewTable!");
        },

        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
    }
}

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(_) => {}
    }
}

fn walk_table(table: AnyLuaValue, names: &[String]) -> Option<AnyLuaValue> {
    if let Some(name) = names.first() {
        if let AnyLuaValue::LuaArray(arr) = table {
            for (key, val) in arr {
                if let AnyLuaValue::LuaString(key_str) = key {
                    if *key_str == *name {
                        return walk_table(val, &names[1..]);
                    }
                }
            }
        }
        return None;
    }
    return Some(table); // ???
}

/*
fn set_value<'l>(lua: &'l mut Lua, mut table: PushGuard<LuaTable<Lua>>,
             names: &[String], val: AnyLuaValue) {
    // Should not be reached!
    if names.len() == 0 {
        return;
    }
    // The last name is the name of the value
    else if names.len() == 1 {
        table.set(names[0].clone(), val);
    }
    else {
        let maybe_table = table.get::<_, _>(names[0]);
        match maybe_table {
            Some(new_table) => {
                set_value(&mut lua, new_table, &names[1..], val);
            }
            None => { return; }
        }
    }
}*/

/// Converts a Json map into an AnyLuaValue
pub fn json_to_lua(json: Json) -> AnyLuaValue {
    match json {
        Json::String(val)  => AnyLuaValue::LuaString(val),
        Json::Boolean(val) => AnyLuaValue::LuaBoolean(val),
        Json::F64(val)     => AnyLuaValue::LuaNumber(val),
        Json::I64(val)     => AnyLuaValue::LuaNumber((val as i32) as f64),
        Json::U64(val)     => AnyLuaValue::LuaNumber((val as u32) as f64),
        Json::Null         => AnyLuaValue::LuaNil,
        Json::Array(vals)  => {
            let mut lua_arr = Vec::with_capacity(vals.len());
            for (ix, val) in vals.into_iter().enumerate() {
                lua_arr.push((AnyLuaValue::LuaNumber(ix as f64 + 1.0),
                              json_to_lua(val)));
            }
            AnyLuaValue::LuaArray(lua_arr)
        },
        Json::Object(vals) => {
            let mut lua_table = Vec::with_capacity(vals.len());
            for (key, val) in vals.into_iter() {
                lua_table.push((AnyLuaValue::LuaString(key),
                                json_to_lua(val)));
            }
            AnyLuaValue::LuaArray(lua_table)
        }
    }
}

/// Converts an `AnyLuaValue` to a `Json`.
///
/// For an already-matched `LuaArray`, use `lua_array_to_json`.
///
/// For a `LuaArray` that should be mapped to a `JsonObject`,
/// use `lua_object_to_json`.
pub fn lua_to_json(lua: AnyLuaValue) -> Result<Json, ()> {
    match lua {
        AnyLuaValue::LuaNil => Ok(Json::Null),
        AnyLuaValue::LuaString(val) => Ok(Json::String(val)),
        AnyLuaValue::LuaNumber(val) => Ok(Json::F64(val)),
        AnyLuaValue::LuaBoolean(val) => Ok(Json::Boolean(val)),
        AnyLuaValue::LuaArray(arr) => lua_array_to_json(arr),
        AnyLuaValue::LuaOther => Err(())
    }
}

pub fn lua_array_to_json(arr: Vec<(AnyLuaValue, AnyLuaValue)>)
                         -> Result<Json, ()> {
    // Check if every key is a number
    let mut counter = 0.0; // Account for first index?

    for &(ref key, ref _val) in &arr {
        match *key {
            AnyLuaValue::LuaNumber(num) => {
                counter += num;
            }
            AnyLuaValue::LuaString(_) => {
                break;
            }
            // Non-string keys are not allowed
            _ => {
                return Err(());
            }
        }
    }

    // Gauss' trick
    let desired_sum = ((arr.len()) * (arr.len() + 1)) / 2;
    if counter != desired_sum as f64 {
        return lua_object_to_json(arr);
    }

    let mut json_arr: Vec<Json> = Vec::with_capacity(arr.len());

    for (_key, val) in arr.into_iter() {
        let lua_val = try!(lua_to_json(val));
        json_arr.push(lua_val);
    }
    Ok(Json::Array(json_arr))
}

pub fn lua_object_to_json(obj: Vec<(AnyLuaValue, AnyLuaValue)>)
                          -> Result<Json, ()> {
    let mut json_obj: BTreeMap<String, Json> = BTreeMap::new();

    for (key, val) in obj.into_iter() {
        match key {
            AnyLuaValue::LuaString(text) => {
                json_obj.insert(text, try!(lua_to_json(val)));
            },
            AnyLuaValue::LuaNumber(ix) => {
                json_obj.insert(format!("{}", ix), try!(lua_to_json(val)));
            }
            _ => { return Err(()); }
        }
    }
    Ok(Json::Object(json_obj))
}
<|endoftext|>


<commit_before>//! The Adapter manager
//!
//! This structure serves two roles:
//! - adapters use it to (un)register themselves, as well as services and channels;
//! - it exposes an implementation of the taxonomy API.

use backend::*;
use adapter::{ Adapter, AdapterManagerHandle };

use foxbox_taxonomy::api::{ AdapterError, API, Error as APIError, ResultMap, WatchEvent };
use foxbox_taxonomy::selector::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::util::*;
use foxbox_taxonomy::values::{ Range, Value };

use std::sync::{ Arc, Mutex };

/// An implementation of the AdapterManager.
pub struct AdapterManager {
    back_end: Arc<Mutex<AdapterManagerState>>,
}

impl AdapterManager {
    /// Create an empty AdapterManager.
    /// This function does not attempt to load any state from the disk.
    pub fn new() -> Self {
        let back_end = Arc::new(Mutex::new(AdapterManagerState::new()));
        AdapterManager {
            back_end: back_end,
        }
    }
}

impl Default for AdapterManager {
    fn default() -> Self {
        Self::new()
    }
}

impl AdapterManagerHandle for AdapterManager {
    /// Add an adapter to the system.
    ///
    /// # Errors
    ///
    /// Returns an error if an adapter with the same id is already present.
    fn add_adapter(&self, adapter: Box<Adapter>, services: Vec<Service>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().add_adapter(adapter, services)
    }

    /// Remove an adapter from the system, including all its services and channels.
    ///
    /// # Errors
    ///
    /// Returns an error if no adapter with this identifier exists. Otherwise, attempts
    /// to cleanup as much as possible, even if for some reason the system is in an
    /// inconsistent state.
    fn remove_adapter(&self, id: &Id<AdapterId>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().remove_adapter(id)
    }

    /// Add a service to the system. Called by the adapter when a new
    /// service (typically a new device) has been detected/configured.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter does not exist or a service with the same identifier
    /// already exists, or if the identifier introduces a channel that would overwrite another
    /// channel with the same identifier. In either cases, this method reverts all its changes.
    fn add_service(&self, service: Service) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().add_service(service)
    }

    /// Remove a service previously registered on the system. Typically, called by
    /// an adapter when a service (e.g. a device) is disconnected.
    ///
    /// # AdapterError
    ///
    /// This method returns an error if the adapter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_service(&self, service_id: &Id<ServiceId>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().remove_service(service_id)
    }

    /// Add a setter to the system. Typically, this is called by the adapter when a new
    /// service has been detected/configured. Some services may gain/lose getters at
    /// runtime depending on their configuration.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter is not registered, the parent service is not
    /// registered, or a channel with the same identifier is already registered.
    /// In either cases, this method reverts all its changes.
    fn add_getter(&self, getter: Channel<Getter>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().add_getter(getter)
    }

    /// Remove a setter previously registered on the system. Typically, called by
    /// an adapter when a service is reconfigured to remove one of its getters.
    ///
    /// # AdapterError
    ///
    /// This method returns an error if the setter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_getter(&self, id: &Id<Getter>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().remove_getter(id)
    }

    /// Add a setter to the system. Typically, this is called by the adapter when a new
    /// service has been detected/configured. Some services may gain/lose setters at
    /// runtime depending on their configuration.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter is not registered, the parent service is not
    /// registered, or a channel with the same identifier is already registered.
    /// In either cases, this method reverts all its changes.
    fn add_setter(&self, setter: Channel<Setter>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().add_setter(setter)
    }

    /// Remove a setter previously registered on the system. Typically, called by
    /// an adapter when a service is reconfigured to remove one of its setters.
    ///
    /// # AdapterError
    ///
    /// This method returns an error if the setter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_setter(&self, id: &Id<Setter>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().remove_setter(id)
    }
}

/// A handle to the public API.
impl API for AdapterManager {
    /// Get the metadata on services matching some conditions.
    ///
    /// A call to `API::get_services(vec![req1, req2, ...])` will return
    /// the metadata on all services matching _either_ `req1` or `req2`
    /// or ...
    fn get_services(&self, selectors: &[ServiceSelector]) -> Vec<Service> {
        self.back_end.lock().unwrap().get_services(selectors)
    }

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    fn add_service_tags(&self, selectors: &[ServiceSelector], tags: &[String]) -> usize {
        self.back_end.lock().unwrap().add_service_tags(selectors, tags)
    }

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    fn remove_service_tags(&self, selectors: &[ServiceSelector], tags: &[String]) -> usize {
        self.back_end.lock().unwrap().remove_service_tags(selectors, tags)
    }

    /// Get a list of channels matching some conditions
    fn get_getter_channels(&self, selectors: &[GetterSelector]) -> Vec<Channel<Getter>> {
        self.back_end.lock().unwrap().get_getter_channels(selectors)
    }
    fn get_setter_channels(&self, selectors: &[SetterSelector]) -> Vec<Channel<Setter>> {
        self.back_end.lock().unwrap().get_setter_channels(selectors)
    }

    /// Label a set of channels with a set of tags.
    ///
    /// A call to `API::put_{setter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the channels matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    fn add_getter_tags(&self, selectors: &[GetterSelector], tags: &[String]) -> usize {
        self.back_end.lock().unwrap().add_getter_tags(selectors, tags)

    }
    fn add_setter_tags(&self, selectors: &[SetterSelector], tags: &[String]) -> usize {
        self.back_end.lock().unwrap().add_setter_tags(selectors, tags)
    }

    /// Remove a set of tags from a set of channels.
    ///
    /// A call to `API::delete_{setter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the channels matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    fn remove_getter_tags(&self, selectors: &[GetterSelector], tags: &[String]) -> usize {
        self.back_end.lock().unwrap().remove_getter_tags(selectors, tags)
    }
    fn remove_setter_tags(&self, selectors: &[SetterSelector], tags: &[String]) -> usize {
        self.back_end.lock().unwrap().remove_setter_tags(selectors, tags)
    }

    /// Read the latest value from a set of channels
    fn fetch_values(&self, selectors: &[GetterSelector]) ->
        ResultMap<Id<Getter>, Option<Value>, APIError>
    {
        self.back_end.lock().unwrap().fetch_values(selectors)
    }

    /// Send a bunch of values to a set of channels
    fn send_values(&self, keyvalues: Vec<(Vec<SetterSelector>, Value)>) ->
        ResultMap<Id<Setter>, (), APIError>
    {
        self.back_end.lock().unwrap().send_values(keyvalues)
    }

    /// Watch for any change
    fn register_channel_watch(&self, selectors: Vec<GetterSelector>, range: Exactly<Range>,
        on_event: Box<Fn(WatchEvent)>) -> Self::WatchGuard
    {
        let (key, is_dropped) = self.back_end.lock().unwrap().register_channel_watch(selectors,
            range, on_event);
        WatchGuard::new(self.back_end.clone(), key, is_dropped)
    }

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard = WatchGuard;
}<commit_msg>Trivial alpha-conversion, to make doc more uniform<commit_after>//! The Adapter manager
//!
//! This structure serves two roles:
//! - adapters use it to (un)register themselves, as well as services and channels;
//! - it exposes an implementation of the taxonomy API.

use backend::*;
use adapter::{ Adapter, AdapterManagerHandle };

use foxbox_taxonomy::api::{ AdapterError, API, Error as APIError, ResultMap, WatchEvent };
use foxbox_taxonomy::selector::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::util::*;
use foxbox_taxonomy::values::{ Range, Value };

use std::sync::{ Arc, Mutex };

/// An implementation of the AdapterManager.
pub struct AdapterManager {
    back_end: Arc<Mutex<AdapterManagerState>>,
}

impl AdapterManager {
    /// Create an empty AdapterManager.
    /// This function does not attempt to load any state from the disk.
    pub fn new() -> Self {
        let back_end = Arc::new(Mutex::new(AdapterManagerState::new()));
        AdapterManager {
            back_end: back_end,
        }
    }
}

impl Default for AdapterManager {
    fn default() -> Self {
        Self::new()
    }
}

impl AdapterManagerHandle for AdapterManager {
    /// Add an adapter to the system.
    ///
    /// # Errors
    ///
    /// Returns an error if an adapter with the same id is already present.
    fn add_adapter(&self, adapter: Box<Adapter>, services: Vec<Service>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().add_adapter(adapter, services)
    }

    /// Remove an adapter from the system, including all its services and channels.
    ///
    /// # Errors
    ///
    /// Returns an error if no adapter with this identifier exists. Otherwise, attempts
    /// to cleanup as much as possible, even if for some reason the system is in an
    /// inconsistent state.
    fn remove_adapter(&self, id: &Id<AdapterId>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().remove_adapter(id)
    }

    /// Add a service to the system. Called by the adapter when a new
    /// service (typically a new device) has been detected/configured.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter does not exist or a service with the same identifier
    /// already exists, or if the identifier introduces a channel that would overwrite another
    /// channel with the same identifier. In either cases, this method reverts all its changes.
    fn add_service(&self, service: Service) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().add_service(service)
    }

    /// Remove a service previously registered on the system. Typically, called by
    /// an adapter when a service (e.g. a device) is disconnected.
    ///
    /// # AdapterError
    ///
    /// This method returns an error if the adapter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_service(&self, id: &Id<ServiceId>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().remove_service(id)
    }

    /// Add a setter to the system. Typically, this is called by the adapter when a new
    /// service has been detected/configured. Some services may gain/lose getters at
    /// runtime depending on their configuration.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter is not registered, the parent service is not
    /// registered, or a channel with the same identifier is already registered.
    /// In either cases, this method reverts all its changes.
    fn add_getter(&self, getter: Channel<Getter>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().add_getter(getter)
    }

    /// Remove a setter previously registered on the system. Typically, called by
    /// an adapter when a service is reconfigured to remove one of its getters.
    ///
    /// # AdapterError
    ///
    /// This method returns an error if the setter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_getter(&self, id: &Id<Getter>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().remove_getter(id)
    }

    /// Add a setter to the system. Typically, this is called by the adapter when a new
    /// service has been detected/configured. Some services may gain/lose setters at
    /// runtime depending on their configuration.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter is not registered, the parent service is not
    /// registered, or a channel with the same identifier is already registered.
    /// In either cases, this method reverts all its changes.
    fn add_setter(&self, setter: Channel<Setter>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().add_setter(setter)
    }

    /// Remove a setter previously registered on the system. Typically, called by
    /// an adapter when a service is reconfigured to remove one of its setters.
    ///
    /// # AdapterError
    ///
    /// This method returns an error if the setter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_setter(&self, id: &Id<Setter>) -> Result<(), AdapterError> {
        self.back_end.lock().unwrap().remove_setter(id)
    }
}

/// A handle to the public API.
impl API for AdapterManager {
    /// Get the metadata on services matching some conditions.
    ///
    /// A call to `API::get_services(vec![req1, req2, ...])` will return
    /// the metadata on all services matching _either_ `req1` or `req2`
    /// or ...
    fn get_services(&self, selectors: &[ServiceSelector]) -> Vec<Service> {
        self.back_end.lock().unwrap().get_services(selectors)
    }

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    fn add_service_tags(&self, selectors: &[ServiceSelector], tags: &[String]) -> usize {
        self.back_end.lock().unwrap().add_service_tags(selectors, tags)
    }

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    fn remove_service_tags(&self, selectors: &[ServiceSelector], tags: &[String]) -> usize {
        self.back_end.lock().unwrap().remove_service_tags(selectors, tags)
    }

    /// Get a list of channels matching some conditions
    fn get_getter_channels(&self, selectors: &[GetterSelector]) -> Vec<Channel<Getter>> {
        self.back_end.lock().unwrap().get_getter_channels(selectors)
    }
    fn get_setter_channels(&self, selectors: &[SetterSelector]) -> Vec<Channel<Setter>> {
        self.back_end.lock().unwrap().get_setter_channels(selectors)
    }

    /// Label a set of channels with a set of tags.
    ///
    /// A call to `API::put_{setter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the channels matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    fn add_getter_tags(&self, selectors: &[GetterSelector], tags: &[String]) -> usize {
        self.back_end.lock().unwrap().add_getter_tags(selectors, tags)

    }
    fn add_setter_tags(&self, selectors: &[SetterSelector], tags: &[String]) -> usize {
        self.back_end.lock().unwrap().add_setter_tags(selectors, tags)
    }

    /// Remove a set of tags from a set of channels.
    ///
    /// A call to `API::delete_{setter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the channels matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    fn remove_getter_tags(&self, selectors: &[GetterSelector], tags: &[String]) -> usize {
        self.back_end.lock().unwrap().remove_getter_tags(selectors, tags)
    }
    fn remove_setter_tags(&self, selectors: &[SetterSelector], tags: &[String]) -> usize {
        self.back_end.lock().unwrap().remove_setter_tags(selectors, tags)
    }

    /// Read the latest value from a set of channels
    fn fetch_values(&self, selectors: &[GetterSelector]) ->
        ResultMap<Id<Getter>, Option<Value>, APIError>
    {
        self.back_end.lock().unwrap().fetch_values(selectors)
    }

    /// Send a bunch of values to a set of channels
    fn send_values(&self, keyvalues: Vec<(Vec<SetterSelector>, Value)>) ->
        ResultMap<Id<Setter>, (), APIError>
    {
        self.back_end.lock().unwrap().send_values(keyvalues)
    }

    /// Watch for any change
    fn register_channel_watch(&self, selectors: Vec<GetterSelector>, range: Exactly<Range>,
        on_event: Box<Fn(WatchEvent)>) -> Self::WatchGuard
    {
        let (key, is_dropped) = self.back_end.lock().unwrap().register_channel_watch(selectors,
            range, on_event);
        WatchGuard::new(self.back_end.clone(), key, is_dropped)
    }

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard = WatchGuard;
}<|endoftext|>


<commit_before>/// Given a list of entries `items` and the query string, filter out the
/// matched entries using fuzzy search algorithm.

use std::sync::{Arc, RwLock};

use std::sync::mpsc::Sender;
use event::Event;
use item::{Item, MatchedItem, MatchedRange};
use util::eventbox::EventBox;
use score;

pub struct Matcher {
    tx_output: Sender<MatchedItem>,   // channel to send output to
    eb_req: Arc<EventBox<Event>>,       // event box that recieve requests
    eb_notify: Arc<EventBox<Event>>,    // event box that send out notification
    items: Arc<RwLock<Vec<Item>>>,
    item_pos: usize,
    num_matched: u64,
    query: String,
}

impl Matcher {
    pub fn new(items: Arc<RwLock<Vec<Item>>>, tx_output: Sender<MatchedItem>,
               eb_req: Arc<EventBox<Event>>, eb_notify: Arc<EventBox<Event>>) -> Self {
        Matcher {
            tx_output: tx_output,
            eb_req: eb_req,
            eb_notify: eb_notify,
            items: items,
            item_pos: 0,
            num_matched: 0,
            query: String::new(),
        }
    }

    fn match_str(&self, item: &str) -> bool {
        if self.query == "" {
            return true;
        }

        item.starts_with(&self.query)
    }

    fn match_item(&self, index: usize, item: &str) -> Option<MatchedItem> {
        //let matched_result = score::compute_match_length(item, &self.query);
        let matched_result = score::fuzzy_match(item, &self.query);
        if matched_result == None {
            return None;
        }

        let (score, matched_range) = matched_result.unwrap();

        let mut item = MatchedItem::new(index);
        item.set_matched_range(MatchedRange::Chars(matched_range));
        item.set_score(score);
        Some(item)
    }

    pub fn process(&mut self) {
        let items = self.items.read().unwrap();
        for item in items[self.item_pos..].into_iter() {
            // process the matcher
            //self.tx_output.send(string.clone());
            if let Some(matched) = self.match_item(self.item_pos, &item.text) {
                self.num_matched += 1;
                let _ = self.tx_output.send(matched);
            }

            self.item_pos += 1;
            if (self.item_pos % 1000) == 999 && !self.eb_req.is_empty() {
                break;
            }
        }
        (*self.eb_notify).set(Event::EvMatcherUpdateProcess, Box::new((self.num_matched, items.len() as u64)));
    }

    fn reset_query(&mut self, query: &str) {
        self.query.clear();
        self.query.push_str(query);
        self.num_matched = 0;
        self.item_pos = 0;
    }

    pub fn run(&mut self) {
        loop {
            for (e, val) in (*self.eb_req).wait() {
                match e {
                    Event::EvMatcherNewItem => {}
                    Event::EvMatcherResetQuery => {
                        self.reset_query(&val.downcast::<String>().unwrap());
                    }
                    _ => {}
                }
            }

            self.process()
        }
    }
}

<commit_msg>[matcher] remove unused function<commit_after>/// Given a list of entries `items` and the query string, filter out the
/// matched entries using fuzzy search algorithm.

use std::sync::{Arc, RwLock};

use std::sync::mpsc::Sender;
use event::Event;
use item::{Item, MatchedItem, MatchedRange};
use util::eventbox::EventBox;
use score;

pub struct Matcher {
    tx_output: Sender<MatchedItem>,   // channel to send output to
    eb_req: Arc<EventBox<Event>>,       // event box that recieve requests
    eb_notify: Arc<EventBox<Event>>,    // event box that send out notification
    items: Arc<RwLock<Vec<Item>>>,
    item_pos: usize,
    num_matched: u64,
    query: String,
}

impl Matcher {
    pub fn new(items: Arc<RwLock<Vec<Item>>>, tx_output: Sender<MatchedItem>,
               eb_req: Arc<EventBox<Event>>, eb_notify: Arc<EventBox<Event>>) -> Self {
        Matcher {
            tx_output: tx_output,
            eb_req: eb_req,
            eb_notify: eb_notify,
            items: items,
            item_pos: 0,
            num_matched: 0,
            query: String::new(),
        }
    }

    fn match_item(&self, index: usize, item: &str) -> Option<MatchedItem> {
        //let matched_result = score::compute_match_length(item, &self.query);
        let matched_result = score::fuzzy_match(item, &self.query);
        if matched_result == None {
            return None;
        }

        let (score, matched_range) = matched_result.unwrap();

        let mut item = MatchedItem::new(index);
        item.set_matched_range(MatchedRange::Chars(matched_range));
        item.set_score(score);
        Some(item)
    }

    pub fn process(&mut self) {
        let items = self.items.read().unwrap();
        for item in items[self.item_pos..].into_iter() {
            // process the matcher
            //self.tx_output.send(string.clone());
            if let Some(matched) = self.match_item(self.item_pos, &item.text) {
                self.num_matched += 1;
                let _ = self.tx_output.send(matched);
            }

            self.item_pos += 1;
            if (self.item_pos % 1000) == 999 && !self.eb_req.is_empty() {
                break;
            }
        }
        (*self.eb_notify).set(Event::EvMatcherUpdateProcess, Box::new((self.num_matched, items.len() as u64)));
    }

    fn reset_query(&mut self, query: &str) {
        self.query.clear();
        self.query.push_str(query);
        self.num_matched = 0;
        self.item_pos = 0;
    }

    pub fn run(&mut self) {
        loop {
            for (e, val) in (*self.eb_req).wait() {
                match e {
                    Event::EvMatcherNewItem => {}
                    Event::EvMatcherResetQuery => {
                        self.reset_query(&val.downcast::<String>().unwrap());
                    }
                    _ => {}
                }
            }

            self.process()
        }
    }
}

<|endoftext|>


<commit_before>#![allow(unused_imports)]

use std::io;
use std::process;

use libc;
use tokio_core::reactor::Handle;

use futures::{self, Future, Stream};

use plugin::Plugin;

#[cfg(unix)]
pub fn monitor_signal(handle: &Handle, plugins: Vec<Plugin>) {
    use tokio_signal::unix::Signal;

    // Monitor SIGCHLD, triggered if subprocess (plugin) is exited.
    let fut1 = Signal::new(libc::SIGCHLD, handle)
        .and_then(|signal| {
                      signal.take(1)
                            .for_each(|_| -> Result<(), io::Error> {
                                          error!("Plugin exited unexpectly (SIGCHLD)");
                                          Ok(())
                                      })
                            .map(|_| libc::SIGCHLD)
                  })
        .map_err(|err| {
                     error!("Failed to monitor SIGCHLD, err: {:?}", err);
                 });

    // Monitor SIGTERM, triggered if shadowsocks is exited gracefully. (Kill by user).
    let fut2 = Signal::new(libc::SIGTERM, handle)
        .and_then(|sigterm| {
                      sigterm.take(1)
                             .for_each(|_| -> Result<(), io::Error> {
                                           info!("Received SIGTERM, exiting.");
                                           Ok(())
                                       })
                             .map(|_| libc::SIGTERM)
                  })
        .map_err(|err| {
                     error!("Failed to monitor SIGTERM, err: {:?}", err);
                 });

    // Monitor SIGINT, triggered by CTRL-C
    let fut3 = Signal::new(libc::SIGINT, handle)
        .and_then(|sigint| {
                      sigint.take(1)
                            .for_each(|_| -> Result<(), io::Error> {
                                          info!("Received SIGINT, exiting.");
                                          Ok(())
                                      })
                            .map(|_| libc::SIGINT)
                  })
        .map_err(|err| {
                     error!("Failed to monitor SIGINT, err: {:?}", err);
                 });

    // Join them all, if any of them is triggered, kill all subprocesses and exit.
    let fut = fut1.select(fut2)
                  .map(|(sig, _)| sig)
                  .map_err(|(e, _)| e)
                  .select(fut3)
                  .map(|(sig, _)| sig)
                  .map_err(|(e, _)| e)
                  .then(|r| {
        // Something happened ... killing all subprocesses
        info!("Killing {} plugins and then exit", plugins.len());
        drop(plugins);

        match r {
            Ok(_signo) => {
                process::exit(0);
            }
            Err(..) => Err(()),
        }
    });

    handle.spawn(fut);
}

#[cfg(windows)]
pub fn monitor_signal(handle: &Handle, plugins: Vec<Plugin>) {
    // FIXME: How to handle SIGTERM equavalent in Windows?

    use tokio_signal::windows::Event;

    let fut1 = Event::ctrl_c(handle)
        .and_then(|ev| {
                      ev.take(1).for_each(|_| -> Result<(), io::Error> {
                                              error!("Received Ctrl-C event");
                                              Ok(())
                                          })
                  })
        .map_err(|err| {
                     error!("Failed to monitor Ctrl-C event: {:?}", err);
                 });

    let fut2 = Event::ctrl_break(handle)
        .and_then(|ev| {
                      ev.take(1).for_each(|_| -> Result<(), io::Error> {
                                              error!("Received Ctrl-Break event");
                                              Ok(())
                                          })
                  })
        .map_err(|err| {
                     error!("Failed to monitor Ctrl-Break event: {:?}", err);
                 });

    let fut = fut1.select(fut2).then(|_| -> Result<(), ()> {
                                         // Something happened ... killing all subprocesses
                                         info!("Killing {} plugins and then exit", plugins.len());
                                         drop(plugins);
                                         process::exit(libc::EXIT_FAILURE);
                                     });
    handle.spawn(fut);
}

#[cfg(not(any(windows, unix)))]
pub fn monitor_signal(handle: &Handle, plugins: Vec<Plugin>) {
    // FIXME: What can I do ...
    // Blocks forever
    let fut = futures::empty::<(), ()>().and_then(|_| { drop(plugins); });
    handle.spawn(fut);
}
<commit_msg>Moe exit message<commit_after>#![allow(unused_imports)]

use std::io;
use std::process;

use libc;
use tokio_core::reactor::Handle;

use futures::{self, Future, Stream};

use plugin::Plugin;

#[cfg(unix)]
pub fn monitor_signal(handle: &Handle, plugins: Vec<Plugin>) {
    use tokio_signal::unix::Signal;

    // Monitor SIGCHLD, triggered if subprocess (plugin) is exited.
    let fut1 = Signal::new(libc::SIGCHLD, handle).and_then(|signal| {
        signal.take(1)
              .for_each(|_| -> Result<(), io::Error> {
                            error!("Plugin exited unexpectly (SIGCHLD)");
                            Ok(())
                        })
              .map(|_| libc::SIGCHLD)
    })
                                                 .map_err(|err| {
                                                              error!("Failed to monitor SIGCHLD, err: {:?}", err);
                                                          });

    // Monitor SIGTERM, triggered if shadowsocks is exited gracefully. (Kill by user).
    let fut2 = Signal::new(libc::SIGTERM, handle).and_then(|sigterm| {
                                                               sigterm.take(1)
                                                                      .for_each(|_| -> Result<(), io::Error> {
                                                                                info!("Received SIGTERM, exiting.");
                                                                                Ok(())
                                                                                })
                                                                      .map(|_| libc::SIGTERM)
                                                           })
                                                 .map_err(|err| {
                                                              error!("Failed to monitor SIGTERM, err: {:?}", err);
                                                          });

    // Monitor SIGINT, triggered by CTRL-C
    let fut3 = Signal::new(libc::SIGINT, handle).and_then(|sigint| {
                                                              sigint.take(1)
                                                                    .for_each(|_| -> Result<(), io::Error> {
                                                                                info!("Received SIGINT, exiting.");
                                                                                Ok(())
                                                                              })
                                                                    .map(|_| libc::SIGINT)
                                                          })
                                                .map_err(|err| {
                                                             error!("Failed to monitor SIGINT, err: {:?}", err);
                                                         });

    // Join them all, if any of them is triggered, kill all subprocesses and exit.
    let fut = fut1.select(fut2)
                  .map(|(sig, _)| sig)
                  .map_err(|(e, _)| e)
                  .select(fut3)
                  .map(|(sig, _)| sig)
                  .map_err(|(e, _)| e)
                  .then(|r| {
        // Something happened ... killing all subprocesses
        info!("Killing {} plugin(s) and then ... Bye Bye :)", plugins.len());
        drop(plugins);

        match r {
            Ok(_signo) => {
                process::exit(0);
            }
            Err(..) => Err(()),
        }
    });

    handle.spawn(fut);
}

#[cfg(windows)]
pub fn monitor_signal(handle: &Handle, plugins: Vec<Plugin>) {
    // FIXME: How to handle SIGTERM equavalent in Windows?

    use tokio_signal::windows::Event;

    let fut1 = Event::ctrl_c(handle).and_then(|ev| {
                                                  ev.take(1).for_each(|_| -> Result<(), io::Error> {
                                                                          error!("Received Ctrl-C event");
                                                                          Ok(())
                                                                      })
                                              })
                                    .map_err(|err| {
                                                 error!("Failed to monitor Ctrl-C event: {:?}", err);
                                             });

    let fut2 = Event::ctrl_break(handle).and_then(|ev| {
                                                      ev.take(1).for_each(|_| -> Result<(), io::Error> {
                                                                              error!("Received Ctrl-Break event");
                                                                              Ok(())
                                                                          })
                                                  })
                                        .map_err(|err| {
                                                     error!("Failed to monitor Ctrl-Break event: {:?}", err);
                                                 });

    let fut = fut1.select(fut2).then(|_| -> Result<(), ()> {
                                         // Something happened ... killing all subprocesses
                                         info!("Killing {} plugin(s) and then ... Bye Bye :)", plugins.len());
                                         drop(plugins);
                                         process::exit(libc::EXIT_FAILURE);
                                     });
    handle.spawn(fut);
}

#[cfg(not(any(windows, unix)))]
pub fn monitor_signal(handle: &Handle, plugins: Vec<Plugin>) {
    // FIXME: What can I do ...
    // Blocks forever
    let fut = futures::empty::<(), ()>().and_then(|_| {
                                                      drop(plugins);
                                                  });
    handle.spawn(fut);
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2015 Rustcc Developers

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::ops::{Deref, DerefMut};
use std::io;
use std::net::SocketAddr;

use mio::Interest;
use mio::buf::{Buf, MutBuf};

use processor::Processor;

pub struct UdpSocket(::mio::udp::UdpSocket);

impl UdpSocket {
    /// Returns a new, unbound, non-blocking, IPv4 UDP socket
    pub fn v4() -> io::Result<UdpSocket> {
        Ok(UdpSocket(try!(::mio::udp::UdpSocket::v4())))
    }

    /// Returns a new, unbound, non-blocking, IPv6 UDP socket
    pub fn v6() -> io::Result<UdpSocket> {
        Ok(UdpSocket(try!(::mio::udp::UdpSocket::v6())))
    }

    pub fn bound(addr: &SocketAddr) -> io::Result<UdpSocket> {
        Ok(UdpSocket(try!(::mio::udp::UdpSocket::bound(addr))))
    }

    pub fn try_clone(&self) -> io::Result<UdpSocket> {
        Ok(UdpSocket(try!(self.0.try_clone())))
    }

    pub fn send_to<B: Buf>(&self, buf: &mut B, target: &SocketAddr) -> io::Result<Option<()>> {
        match try!(self.0.send_to(buf, target)) {
            None => {
                debug!("UdpSocket send_to WOULDBLOCK");
            },
            Some(..) => {
                return Ok(Some(()));
            }
        }

        try!(Processor::current().wait_event(&self.0, Interest::writable()));

        match try!(self.0.send_to(buf, target)) {
            None => {
                panic!("UdpSocket send_to WOULDBLOCK");
            },
            Some(..) => {
                return Ok(Some(()));
            }
        }
    }

    pub fn recv_from<B: MutBuf>(&self, buf: &mut B) -> io::Result<Option<SocketAddr>> {
        match try!(self.0.recv_from(buf)) {
            None => {
                debug!("UdpSocket recv_from WOULDBLOCK");
            },
            Some(addr) => {
                return Ok(Some(addr));
            }
        }

        try!(Processor::current().wait_event(&self.0, Interest::readable()));

        match try!(self.0.recv_from(buf)) {
            None => {
                panic!("UdpSocket recv_from WOULDBLOCK");
            },
            Some(addr) => {
                return Ok(Some(addr));
            }
        }
    }
}

impl Deref for UdpSocket {
    type Target = ::mio::udp::UdpSocket;

    fn deref(&self) -> &::mio::udp::UdpSocket {
        return &self.0
    }
}

impl DerefMut for UdpSocket {
    fn deref_mut(&mut self) -> &mut ::mio::udp::UdpSocket {
        return &mut self.0
    }
}
<commit_msg>use std::net::udp apis<commit_after>// The MIT License (MIT)

// Copyright (c) 2015 Rustcc Developers

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::ops::{Deref, DerefMut};
use std::io;
use std::net::{ToSocketAddrs, SocketAddr};

use mio::Interest;
use mio::buf::{Buf, MutBuf, SliceBuf, MutSliceBuf};

use processor::Processor;

pub struct UdpSocket(::mio::udp::UdpSocket);

impl UdpSocket {
    /// Returns a new, unbound, non-blocking, IPv4 UDP socket
    pub fn v4() -> io::Result<UdpSocket> {
        Ok(UdpSocket(try!(::mio::udp::UdpSocket::v4())))
    }

    /// Returns a new, unbound, non-blocking, IPv6 UDP socket
    pub fn v6() -> io::Result<UdpSocket> {
        Ok(UdpSocket(try!(::mio::udp::UdpSocket::v6())))
    }

    pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
        super::each_addr(addr, |a| {
            ::mio::udp::UdpSocket::bound(&a)
        }).map(UdpSocket)
    }

    pub fn try_clone(&self) -> io::Result<UdpSocket> {
        Ok(UdpSocket(try!(self.0.try_clone())))
    }

    pub fn send_to<A: ToSocketAddrs>(&self, slice_buf: &[u8], target: A) -> io::Result<usize> {
        let mut buf = SliceBuf::wrap(slice_buf);

        let mut last_err = Ok(0);
        for addr in try!(target.to_socket_addrs()) {
            match self.0.send_to(&mut buf, &addr) {
                Ok(None) => {
                    debug!("UdpSocket send_to WOULDBLOCK");
                    break;
                },
                Ok(Some(..)) => {
                    return Ok(slice_buf.len() - buf.remaining());
                },
                Err(err) => last_err = Err(err),
            }
        }

        if last_err.is_err() {
            return last_err;
        }

        for addr in try!(target.to_socket_addrs()) {
            loop {
                try!(Processor::current().wait_event(&self.0, Interest::writable()));

                match self.0.send_to(&mut buf, &addr) {
                    Ok(None) => {
                        warn!("UdpSocket send_to WOULDBLOCK");
                    },
                    Ok(Some(..)) => {
                        return Ok(slice_buf.len() - buf.remaining());
                    },
                    Err(err) => {
                        last_err = Err(err);
                        break;
                    }
                }
            }
        }

        last_err
    }

    pub fn recv_from(&self, slice_buf: &mut [u8]) -> io::Result<Option<SocketAddr>> {
        let mut buf = MutSliceBuf::wrap(slice_buf);

        match try!(self.0.recv_from(&mut buf)) {
            None => {
                debug!("UdpSocket recv_from WOULDBLOCK");
            },
            Some(addr) => {
                return Ok(Some(addr));
            }
        }

        loop {
            try!(Processor::current().wait_event(&self.0, Interest::readable()));

            match try!(self.0.recv_from(&mut buf)) {
                None => {
                    warn!("UdpSocket recv_from WOULDBLOCK");
                },
                Some(addr) => {
                    return Ok(Some(addr));
                }
            }
        }
    }
}

impl Deref for UdpSocket {
    type Target = ::mio::udp::UdpSocket;

    fn deref(&self) -> &::mio::udp::UdpSocket {
        return &self.0
    }
}

impl DerefMut for UdpSocket {
    fn deref_mut(&mut self) -> &mut ::mio::udp::UdpSocket {
        return &mut self.0
    }
}
<|endoftext|>


<commit_before>use memory::{EmptyMemory, Memory, pack_u16, high_byte, low_byte, low_nibble, high_nibble};
use extensions::Incrementor;
use cpu::{Register, Flags, CarryFlag, HalfCarryFlag, ZeroFlag, SubtractFlag};
use ops::u8_immediate;

fn half_carry_for_subtract(val1: u8, val2: u8, carry: u8) -> bool {
    if low_nibble(val2) + carry == 0x10 && val1 >= 0x10 {
        return true;
    } else {
        return low_nibble(val1) >= (low_nibble(val2) + carry);
    }

}

pub fn sub_u8_immediate(mem: &Memory, pc: &mut Register<u16>, reg: &mut Register<u8>, freg: &mut Register<Flags>, with_carry: bool) {
    let val = u8_immediate(mem, pc);
    internal_sub(reg, val, freg, with_carry);
}

fn carry_for_subtract(val1: u8, val2: u8, carry: u8) -> bool {
    return val1 as u16 >= (val2 as u16 + carry as u16);
}

pub fn internal_sub(reg: &mut Register<u8>, val: u8, freg: &mut Register<Flags>, with_carry: bool) {
    let reg_val = reg.read();
    let mut flags = SubtractFlag;
    let mut carry = 0;

    if freg.read().contains(CarryFlag) && with_carry {
        carry = 1;
    }

    if half_carry_for_subtract(reg_val, val, carry) {
        flags.insert(HalfCarryFlag);
    }

    if carry_for_subtract(reg_val, val, carry) {
        flags.insert(CarryFlag);
    }

    let result = reg_val.wrapping_sub(val).wrapping_sub(carry);

    if result == 0 {
        flags.insert(ZeroFlag);
    }
    debug!("internal sub result {:X}", result);
    reg.write(result);
    freg.write(flags);
}

pub fn sub(reg: &mut Register<u8>, val: u8, freg: &mut Register<Flags>) {
    internal_sub(reg, val, freg, false);
}

pub fn sbc(reg: &mut Register<u8>, val: u8, freg: &mut Register<Flags>) {
    internal_sub(reg, val, freg, true);
}

pub fn sub_value_at_address(mem: &Memory, reg: &mut Register<u8>, addr: u16, freg: &mut Register<Flags>) {
    let val = mem.read_byte(addr);
    internal_sub(reg, val, freg, false);
}

pub fn sbc_value_at_address(mem: &Memory, reg: &mut Register<u8>, addr: u16, freg: &mut Register<Flags>) {
    let val = mem.read_byte(addr);
    internal_sub(reg, val, freg, true);
}

pub fn compare(reg: &mut Register<u8>, val: u8, freg: &mut Register<Flags>) {
    let reg_val = reg.read();
    let mut flags = SubtractFlag;
    let mut carry = 0;

    if half_carry_for_subtract(reg_val, val, carry) {
        flags.insert(HalfCarryFlag);
    }

    if carry_for_subtract(reg_val, val, carry) {
        flags.insert(CarryFlag);
    }

    if (reg_val == val) {
        flags.insert(ZeroFlag);
    }
    freg.write(flags);
}

pub fn compare_value_at_address(mem: &Memory, reg: &mut Register<u8>, addr: u16, freg: &mut Register<Flags>) {
    let val = mem.read_byte(addr);
    compare(reg, val, freg);
}

/// Decrement register by 1
/// Set ZeroFlag if result is 0
/// Set SubtractFlag
/// Set HalfCarryFlag if there is no borrow from bit 4
pub fn decrement_register(reg: &mut Register<u8>, freg: &mut Register<Flags>) {
    let val = reg.read();
    let mut flags = freg.read() | SubtractFlag;
    flags.remove(ZeroFlag);
    flags.remove(HalfCarryFlag);

    if (val & 0x0F) > 0 {
        flags = flags | HalfCarryFlag;
    }

    reg.decrement();

    if reg.read() == 0x00 {
        flags = flags | ZeroFlag;
    }
    freg.write(flags);
}

pub fn decrement_register_pair(reg1: &mut Register<u8>, reg2: &mut Register<u8>) {
    let val = pack_u16(reg1.read(), reg2.read());
    let ans = val - 1;

    reg1.write(high_byte(ans));
    reg2.write(low_byte(ans));
}

pub fn decrement_value_at_address(mem: &mut Memory, hb: u8, lb: u8, freg: &mut Register<Flags>) {
    let addr = pack_u16(hb, lb);
    let val = mem.read_byte(addr);
    let mut reg = Register::new(val);
    decrement_register(&mut reg, freg);
    mem.write_byte(addr, reg.read());
}

#[cfg(test)]
mod tests {
    use super::*;
    use memory::{EmptyMemory, Memory, pack_u16, high_byte, low_byte, low_nibble, high_nibble};
    use extensions::Incrementor;
    use cpu::{Register, Flags, CarryFlag, HalfCarryFlag, ZeroFlag, SubtractFlag};

    #[test]
    fn test_sub_u8_immediate() {
        let mut mem = EmptyMemory::new(0xFFFF);
        let mut pc = Register::new(0x2736);
        let mut reg = Register::new(0x35);
        let mut freg = Register::new(Flags::empty());
        mem.write_byte(pc.read(), 0x11);

        sub_u8_immediate(&mem, &mut pc, &mut reg, &mut freg, false);

        assert!(pc.read() == 0x2737);
        assert!(reg.read() == 0x24);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag | CarryFlag);

        mem.write_byte(pc.read(), 0x0C);
        sub_u8_immediate(&mem, &mut pc, &mut reg, &mut freg, false);

        assert!(pc.read() == 0x2738);
        assert!(reg.read() == 0x18);
        assert!(freg.read() == SubtractFlag | CarryFlag);

        mem.write_byte(pc.read(), 0x0F);
        freg.write(CarryFlag);
        sub_u8_immediate(&mem, &mut pc, &mut reg, &mut freg, true);

        assert!(pc.read() == 0x2739);
        assert!(reg.read() == 0x08);
        assert!(freg.read() == SubtractFlag | CarryFlag | HalfCarryFlag);

    }

    #[test]
    fn test_cp() {
        let mut reg = Register::new(0xAA);
        let mut val = 0xBB;
        let mut freg = Register::new(Flags::empty());

        compare(&mut reg, val, &mut freg);
        assert!(reg.read() == 0xAA);
        assert!(freg.read() == SubtractFlag);

        reg.write(0xF0);
        val = 0xF0;
        compare(&mut reg, val, &mut freg);
        assert!(reg.read() == 0xF0);
        assert!(freg.read() == SubtractFlag | CarryFlag | HalfCarryFlag | ZeroFlag);
    }

    #[test]
    fn test_compare_value_at_address() {
        let mut mem = EmptyMemory::new(0xFFFF);
        let mut reg = Register::new(0xBA);
        let mut freg = Register::new(Flags::empty());
        let addr = 0x1239;
        let mut val = 0xAB;
        mem.write_byte(addr, val);

        compare_value_at_address(&mem, &mut reg, addr, &mut freg);
        assert!(reg.read() == 0xBA);
        assert!(freg.read() == SubtractFlag | CarryFlag);

        mem.write_byte(addr, 0xCD);
        reg.write(0xCD);
        compare_value_at_address(&mem, &mut reg, addr, &mut freg);
        assert!(reg.read() == 0xCD);
        assert!(freg.read() == SubtractFlag | ZeroFlag | HalfCarryFlag | CarryFlag);

    }

    #[test]
    fn test_sbc_value_at_address() {
        let mut mem = EmptyMemory::new(0xFFFF);
        let mut freg = Register::new(CarryFlag);
        let mut reg = Register::new(0xFF);
        let addr = 0x1234;
        mem.write_byte(addr, 0xCD);

        sbc_value_at_address(&mem, &mut reg, addr, &mut freg);
        assert!(reg.read() == 0x31);
        assert!(freg.read() == SubtractFlag | CarryFlag | HalfCarryFlag);
    }

    #[test]
    fn test_sub_value_at_address() {
        let mut mem = EmptyMemory::new(0xFFFF);
        let mut freg = Register::new(CarryFlag);
        let mut reg = Register::new(0xFF);
        let addr = 0x1234;
        mem.write_byte(addr, 0xCD);

        sub_value_at_address(&mem, &mut reg, addr, &mut freg);
        assert!(reg.read() == 0x32);
        assert!(freg.read() == SubtractFlag | CarryFlag | HalfCarryFlag);
    }

    #[test]
    fn test_sbc() {
        let mut reg = Register::new(0xFF);
        let mut freg = Register::new(Flags::empty());

        sbc(&mut reg, 0x0f, &mut freg);
        assert!(reg.read() == 0xF0);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag | CarryFlag);

        reg.write(0xFF);
        freg.write(CarryFlag);
        sbc(&mut reg, 0x0f, &mut freg);
        assert!(reg.read() == 0xEF);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag | CarryFlag);

        reg.write(0xFF);
        freg.write(CarryFlag);
        sbc(&mut reg, 0xFF, &mut freg);
        assert!(reg.read() == 0xFF);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag);

        reg.write(0xAB);
        freg.write(CarryFlag);
        sbc(&mut reg, 0x12, &mut freg);
        assert!(reg.read() == 0x98);
        assert!(freg.read() == SubtractFlag | CarryFlag | HalfCarryFlag);
    }

    #[test]
    fn test_sub() {
        let mut reg = Register::new(0xFF);
        let mut freg = Register::new(Flags::empty());

        sub(&mut reg, 0x0f, &mut freg);
        assert!(reg.read() == 0xF0);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag | CarryFlag);

        reg.write(0x11);
        sub(&mut reg, 0x11, &mut freg);
        assert!(reg.read() == 0);
        assert!(freg.read().contains(SubtractFlag));
        assert!(freg.read().contains(ZeroFlag));
        assert!(freg.read().contains(CarryFlag));
        assert!(freg.read().contains(HalfCarryFlag));

        reg.write(0xA0);
        sub(&mut reg, 0xB0, &mut freg);
        assert!(reg.read() == 0xF0);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag);

        reg.write(0x80);
        sub(&mut reg, 0x0f, &mut freg);
        assert!(reg.read() == 0x71);
        assert!(freg.read() == SubtractFlag | CarryFlag);

        reg.write(0x05);
        sub(&mut reg, 0xAB, &mut freg);
        assert!(reg.read() == 0x5A);
        assert!(freg.read() == SubtractFlag);
    }

    #[test]
    fn test_decrement_value_at_address() {
        let mut mem = EmptyMemory::new(0xFFFF);
        let mut freg = Register::new(CarryFlag);
        mem.write_byte(0x1010, 1);

        decrement_value_at_address(&mut mem, 0x10, 0x10, &mut freg);

        assert!(mem.read_byte(0x1010) == 0);
        assert!(freg.read().is_all());

        mem.write_byte(0x01AB, 0x20);

        decrement_value_at_address(&mut mem, 0x01, 0xAB, &mut freg);

        assert!(mem.read_byte(0x01AB) == 0x1F);
        assert!(freg.read() == CarryFlag | SubtractFlag);

        freg.write(ZeroFlag);
        mem.write_byte(0xABCD, 0xED);
        decrement_value_at_address(&mut mem, 0xAB, 0xCD, &mut freg);

        assert!(mem.read_byte(0xABCD) == 0xEC);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag);

    }

    #[test]
    fn test_decrement_register_pair() {
        let mut reg1 = Register::new(0x70);
        let mut reg2 = Register::new(0x00);

        decrement_register_pair(&mut reg1, &mut reg2);

        assert!(reg1.read() == 0x6F);
        assert!(reg2.read() == 0xFF);
    }

    #[test]
    fn test_decrement_register() {
        let mut reg = Register::new(1);
        let mut freg = Register::new(Flags::empty());

        decrement_register(&mut reg, &mut freg);

        assert!(reg.read() == 0);
        assert!(freg.read() == ZeroFlag | SubtractFlag | HalfCarryFlag);

        reg.write(0xF1);
        freg.write(Flags::empty());

        decrement_register(&mut reg, &mut freg);

        assert!(reg.read() == 0xF0);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag);

        reg.write(0xF0);
        freg.write(Flags::empty());

        decrement_register(&mut reg, &mut freg);

        assert!(reg.read() == 0xEF);
        assert!(freg.read() == SubtractFlag);
    }
}
<commit_msg>Fix carry and halfcarry calculation in sub ops<commit_after>use memory::{EmptyMemory, Memory, pack_u16, high_byte, low_byte, low_nibble, high_nibble};
use extensions::Incrementor;
use cpu::{Register, Flags, CarryFlag, HalfCarryFlag, ZeroFlag, SubtractFlag};
use ops::u8_immediate;

fn half_carry_for_subtract(val1: u8, val2: u8, carry: u8) -> bool {
    return (low_nibble(val2) + carry) > low_nibble(val1);
}

pub fn sub_u8_immediate(mem: &Memory, pc: &mut Register<u16>, reg: &mut Register<u8>, freg: &mut Register<Flags>, with_carry: bool) {
    let val = u8_immediate(mem, pc);
    internal_sub(reg, val, freg, with_carry);
}

fn carry_for_subtract(val1: u8, val2: u8, carry: u8) -> bool {
    return (val2 as u16 + carry as u16) > val1 as u16 ;
}

pub fn internal_sub(reg: &mut Register<u8>, val: u8, freg: &mut Register<Flags>, with_carry: bool) {
    let reg_val = reg.read();
    let mut flags = SubtractFlag;
    let mut carry = 0;

    if freg.read().contains(CarryFlag) && with_carry {
        carry = 1;
    }

    if half_carry_for_subtract(reg_val, val, carry) {
        flags.insert(HalfCarryFlag);
    }

    if carry_for_subtract(reg_val, val, carry) {
        flags.insert(CarryFlag);
    }

    let result = reg_val.wrapping_sub(val).wrapping_sub(carry);

    if result == 0 {
        flags.insert(ZeroFlag);
    }
    debug!("internal sub result {:X}", result);
    reg.write(result);
    freg.write(flags);
}

pub fn sub(reg: &mut Register<u8>, val: u8, freg: &mut Register<Flags>) {
    internal_sub(reg, val, freg, false);
}

pub fn sbc(reg: &mut Register<u8>, val: u8, freg: &mut Register<Flags>) {
    internal_sub(reg, val, freg, true);
}

pub fn sub_value_at_address(mem: &Memory, reg: &mut Register<u8>, addr: u16, freg: &mut Register<Flags>) {
    let val = mem.read_byte(addr);
    internal_sub(reg, val, freg, false);
}

pub fn sbc_value_at_address(mem: &Memory, reg: &mut Register<u8>, addr: u16, freg: &mut Register<Flags>) {
    let val = mem.read_byte(addr);
    internal_sub(reg, val, freg, true);
}

pub fn compare(reg: &mut Register<u8>, val: u8, freg: &mut Register<Flags>) {
    let reg_val = reg.read();
    let mut flags = SubtractFlag;
    let mut carry = 0;

    if half_carry_for_subtract(reg_val, val, carry) {
        flags.insert(HalfCarryFlag);
    }

    if carry_for_subtract(reg_val, val, carry) {
        flags.insert(CarryFlag);
    }

    if (reg_val == val) {
        flags.insert(ZeroFlag);
    }
    freg.write(flags);
}

pub fn compare_value_at_address(mem: &Memory, reg: &mut Register<u8>, addr: u16, freg: &mut Register<Flags>) {
    let val = mem.read_byte(addr);
    compare(reg, val, freg);
}

pub fn decrement_register(reg: &mut Register<u8>, freg: &mut Register<Flags>) {
    internal_sub(reg, 1, freg, false);
}

pub fn decrement_register_pair(reg1: &mut Register<u8>, reg2: &mut Register<u8>) {
    let val = pack_u16(reg1.read(), reg2.read());
    let ans = val - 1;

    reg1.write(high_byte(ans));
    reg2.write(low_byte(ans));
}

pub fn decrement_value_at_address(mem: &mut Memory, hb: u8, lb: u8, freg: &mut Register<Flags>) {
    let addr = pack_u16(hb, lb);
    let val = mem.read_byte(addr);
    let mut reg = Register::new(val);
    decrement_register(&mut reg, freg);
    mem.write_byte(addr, reg.read());
}

#[cfg(test)]
mod tests {
    use super::*;
    use memory::{EmptyMemory, Memory, pack_u16, high_byte, low_byte, low_nibble, high_nibble};
    use extensions::Incrementor;
    use cpu::{Register, Flags, CarryFlag, HalfCarryFlag, ZeroFlag, SubtractFlag};

    #[test]
    fn test_sub_u8_immediate() {
        let mut mem = EmptyMemory::new(0xFFFF);
        let mut pc = Register::new(0x2736);
        let mut reg = Register::new(0x35);
        let mut freg = Register::new(Flags::empty());
        mem.write_byte(pc.read(), 0x11);

        sub_u8_immediate(&mem, &mut pc, &mut reg, &mut freg, false);

        assert!(pc.read() == 0x2737);
        assert!(reg.read() == 0x24);
        assert!(freg.read() == SubtractFlag);

        mem.write_byte(pc.read(), 0x0C);
        sub_u8_immediate(&mem, &mut pc, &mut reg, &mut freg, false);

        assert!(pc.read() == 0x2738);
        assert!(reg.read() == 0x18);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag);

        mem.write_byte(pc.read(), 0x0F);
        freg.write(CarryFlag);
        sub_u8_immediate(&mem, &mut pc, &mut reg, &mut freg, true);

        assert!(pc.read() == 0x2739);
        assert!(reg.read() == 0x08);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag);
    }

    #[test]
    fn test_cp() {
        let mut reg = Register::new(0xAA);
        let mut val = 0xBB;
        let mut freg = Register::new(Flags::empty());

        compare(&mut reg, val, &mut freg);
        assert!(reg.read() == 0xAA);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag | CarryFlag);

        reg.write(0xF0);
        val = 0xF0;
        compare(&mut reg, val, &mut freg);
        assert!(reg.read() == 0xF0);
        assert!(freg.read() == SubtractFlag | ZeroFlag);
    }

    #[test]
    fn test_compare_value_at_address() {
        let mut mem = EmptyMemory::new(0xFFFF);
        let mut reg = Register::new(0xBA);
        let mut freg = Register::new(Flags::empty());
        let addr = 0x1239;
        let mut val = 0xAB;
        mem.write_byte(addr, val);

        compare_value_at_address(&mem, &mut reg, addr, &mut freg);
        assert!(reg.read() == 0xBA);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag);

        mem.write_byte(addr, 0xCD);
        reg.write(0xCD);
        compare_value_at_address(&mem, &mut reg, addr, &mut freg);
        assert!(reg.read() == 0xCD);
        assert!(freg.read() == SubtractFlag | ZeroFlag);

        mem.write_byte(addr, 0xCD);
        reg.write(0xCF);
        compare_value_at_address(&mem, &mut reg, addr, &mut freg);
        assert!(reg.read() == 0xCD);
        assert!(freg.read() == SubtractFlag | ZeroFlag | CarryFlag | HalfCarryFlag);

    }

    #[test]
    fn test_sbc_value_at_address() {
        let mut mem = EmptyMemory::new(0xFFFF);
        let mut freg = Register::new(CarryFlag);
        let mut reg = Register::new(0xFF);
        let addr = 0x1234;
        mem.write_byte(addr, 0xCD);

        sbc_value_at_address(&mem, &mut reg, addr, &mut freg);
        assert!(reg.read() == 0x31);
        assert!(freg.read() == SubtractFlag);
    }

    #[test]
    fn test_sub_value_at_address() {
        let mut mem = EmptyMemory::new(0xFFFF);
        let mut freg = Register::new(CarryFlag);
        let mut reg = Register::new(0xFF);
        let addr = 0x1234;
        mem.write_byte(addr, 0xCD);

        sub_value_at_address(&mem, &mut reg, addr, &mut freg);
        assert!(reg.read() == 0x32);
        assert!(freg.read() == SubtractFlag);
    }

    #[test]
    fn test_sbc() {
        let mut reg = Register::new(0xFF);
        let mut freg = Register::new(Flags::empty());

        sbc(&mut reg, 0x0F, &mut freg);
        assert!(reg.read() == 0xF0);
        assert!(freg.read() == SubtractFlag);

        reg.write(0xFF);
        freg.write(CarryFlag);
        sbc(&mut reg, 0x0F, &mut freg);
        assert!(reg.read() == 0xEF);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag);

        reg.write(0xFF);
        freg.write(CarryFlag);
        sbc(&mut reg, 0xFF, &mut freg);
        assert!(reg.read() == 0xFF);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag | CarryFlag);

        reg.write(0xAB);
        freg.write(CarryFlag);
        sbc(&mut reg, 0x12, &mut freg);
        assert!(reg.read() == 0x98);
        assert!(freg.read() == SubtractFlag);
    }

    #[test]
    fn test_sub() {
        let mut reg = Register::new(0xFF);
        let mut freg = Register::new(Flags::empty());

        sub(&mut reg, 0x0F, &mut freg);
        assert!(reg.read() == 0xF0);
        assert!(freg.read() == SubtractFlag);

        reg.write(0x11);
        sub(&mut reg, 0x11, &mut freg);
        assert!(reg.read() == 0);
        assert!(freg.read().contains(SubtractFlag));
        assert!(freg.read().contains(ZeroFlag));

        reg.write(0xA0);
        sub(&mut reg, 0xB0, &mut freg);
        assert!(reg.read() == 0xF0);
        assert!(freg.read() == SubtractFlag | CarryFlag);

        reg.write(0x80);
        sub(&mut reg, 0x0F, &mut freg);
        assert!(reg.read() == 0x71);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag);

        reg.write(0xE5);
        sub(&mut reg, 0xAB, &mut freg);
        assert!(reg.read() == 0x3A);
        assert!(freg.read() == SubtractFlag | HalfCarryFlag);
    }

    #[test]
    fn test_decrement_value_at_address() {
        let mut mem = EmptyMemory::new(0xFFFF);
        let mut freg = Register::new(CarryFlag);
        mem.write_byte(0x1010, 1);

        decrement_value_at_address(&mut mem, 0x10, 0x10, &mut freg);

        assert!(mem.read_byte(0x1010) == 0);
        assert!(freg.read().is_all());

        mem.write_byte(0x01AB, 0x20);

        decrement_value_at_address(&mut mem, 0x01, 0xAB, &mut freg);

        assert!(mem.read_byte(0x01AB) == 0x1F);
        assert!(freg.read() == SubtractFlag);

        freg.write(ZeroFlag);
        mem.write_byte(0xABCD, 0xED);
        decrement_value_at_address(&mut mem, 0xAB, 0xCD, &mut freg);

        assert!(mem.read_byte(0xABCD) == 0xEC);
        assert!(freg.read() == SubtractFlag);

    }

    #[test]
    fn test_decrement_register_pair() {
        let mut reg1 = Register::new(0x70);
        let mut reg2 = Register::new(0x00);

        decrement_register_pair(&mut reg1, &mut reg2);

        assert!(reg1.read() == 0x6F);
        assert!(reg2.read() == 0xFF);
    }

    #[test]
    fn test_decrement_register() {
        let mut reg = Register::new(1);
        let mut freg = Register::new(Flags::empty());

        decrement_register(&mut reg, &mut freg);

        assert!(reg.read() == 0);
        assert!(freg.read() == ZeroFlag | SubtractFlag);

        reg.write(0x0);
        decrement_register(&mut reg, &mut freg);

        assert!(reg.read() == 255);
        assert!(freg.read() == ZeroFlag | SubtractFlag | CarryFlag | HalfCarryFlag);

        reg.write(0xF1);
        freg.write(Flags::empty());

        decrement_register(&mut reg, &mut freg);

        assert!(reg.read() == 0xF0);
        assert!(freg.read() == SubtractFlag);

        reg.write(0xF0);
        freg.write(Flags::empty());

        decrement_register(&mut reg, &mut freg);

        assert!(reg.read() == 0xEF);
        assert!(freg.read() == SubtractFlag);
    }
}
<|endoftext|>