use rlua::{FromLua, Context, Value, Error, ToLua}; use std::convert::TryFrom; #[derive(Hash, Ord, PartialOrd, Eq, PartialEq, Debug, Clone)] pub enum Bind { Mouse(u32), Key(u32), Ping(String), } #[derive(Debug, Clone)] pub struct Handler { pub passthrough: bool, pub action: Action, } #[derive(Debug, Clone)] pub enum Action { Sync(Bind), Press(Bind), Release(Bind), Sleep(u32), List(Vec), } impl<'lua> FromLua<'lua> for Bind { fn from_lua(lua_value: Value<'lua>, _: Context<'lua>) -> Result { if let Value::Integer(n) = lua_value { return Ok(Bind::Key(u32::try_from(n).map_err(|e| Error::external(e))?)); } if let Value::String(c) = lua_value { return Ok(Bind::Ping(String::from(c.to_str()?))); } if let Value::Table(table) = lua_value { let typ: String = table.get("type")?; let bind = match typ.as_str() { "mouse" => Bind::Mouse(table.get("code")?), "key" => Bind::Key(table.get("code")?), "ping" => Bind::Ping(table.get("code")?), _ => return Err(Error::RuntimeError("Type should be one of mouse, key or ping".to_string())) }; return Ok(bind); } Err(Error::RuntimeError("Can't create Bind from non-table".to_string())) } } impl<'lua> ToLua<'lua> for Bind { fn to_lua(self, lua: Context<'lua>) -> Result, Error> { let table = lua.create_table()?; table.set("type", match self { Bind::Key(_) => "key", Bind::Ping(_) => "ping", Bind::Mouse(_) => "mouse", })?; match self { Bind::Key(n) => table.set("code", n)?, Bind::Mouse(n) => table.set("code", n)?, Bind::Ping(c) => table.set("code", c)?, } Ok(table.to_lua(lua)?) } } impl<'lua> FromLua<'lua> for Action { fn from_lua(lua_value: Value<'lua>, _: Context<'lua>) -> Result { let table = if let Value::Table(table) = lua_value { table } else { return Err(Error::RuntimeError("Action should be a table".to_string())); }; let res = match table.get::<&str, String>("type")?.as_str() { "sync" => Action::Sync(table.get("bind")?), "press" => Action::Press(table.get("bind")?), "release" => Action::Release(table.get("bind")?), "sleep" => Action::Sleep(table.get("time")?), "list" => Action::List(table.get("items")?), _ => return Err(Error::RuntimeError("Action type is invalid, should be one of sync, release, press, sleep, list".to_string())) }; Ok(res) } }