diff --git a/src/chunk.rs b/src/chunk.rs index 67cd57f..a247f79 100755 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -70,6 +70,18 @@ impl<'a> IntoChunkData<'a> for &'a str { } } +impl<'a> IntoChunkData<'a> for &'a String { + fn into_chunk(self) -> Cow<'a, [u8]> { + Cow::Borrowed(self.as_bytes()) + } +} + +impl<'a> IntoChunkData<'a> for String { + fn into_chunk(self) -> Cow<'a, [u8]> { + Cow::Owned(self.as_bytes().to_vec()) + } +} + impl<'a> IntoChunkData<'a> for &'a [u8] { fn into_chunk(self) -> Cow<'a, [u8]> { Cow::Borrowed(self) diff --git a/src/lib.rs b/src/lib.rs index 92ac9d5..c737bb4 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,34 +1,38 @@ use mlua_sys as lua; pub mod state; -use state::*; +pub use state::*; pub mod table; -use table::*; +pub use table::*; pub mod function; -use function::*; +pub use function::*; pub mod value; -use value::*; +pub use value::*; pub mod guard; -use guard::*; +pub use guard::*; pub mod userdata; use userdata::*; pub mod util; -use util::*; +#[allow(unused_imports)] +pub use util::*; pub mod chunk; -use chunk::*; +pub use chunk::*; pub mod error; -use error::*; +pub use error::*; pub mod lref; -use lref::*; +pub use lref::*; + +pub mod variadic; +pub use variadic::*; #[cfg(test)] pub mod tests; diff --git a/src/table.rs b/src/table.rs index 8633856..99fd433 100755 --- a/src/table.rs +++ b/src/table.rs @@ -166,7 +166,7 @@ impl<'a> Table<'a> { key_val.push_to_lua_stack(self.state)?; // table[key] is at top of stack - if lua::lua_gettable(s, -2) == lua::LUA_TNIL { + if lua::lua_gettable(s, -2) != lua::LUA_TNIL { Ok(true) } else { Ok(false) diff --git a/src/userdata/any.rs b/src/userdata/any.rs index b4b0e4e..37bc920 100755 --- a/src/userdata/any.rs +++ b/src/userdata/any.rs @@ -2,7 +2,7 @@ use std::{cell::{Ref, RefCell, RefMut}, ffi::CStr}; use mlua_sys as lua; -use crate::{ensure_type, AsLua, FromLua, FromLuaStack, Function, IntoLuaVec, LuaRef, PushToLuaStack, StackGuard, State, Table, Userdata, Value}; +use crate::{ensure_type, AsLua, Error, FromLua, FromLuaStack, Function, IntoLuaVec, LuaRef, MetaMethod, PushToLuaStack, StackGuard, State, Table, Userdata, Value}; /// A handle to some userdata on the stack //#[derive(Clone)] @@ -118,7 +118,7 @@ impl<'a> AnyUserdata<'a> { } /// Returns the metatable of this userdata - pub fn get_metatable(&'a self) -> crate::Result> { + pub fn get_metatable(&self) -> crate::Result> { unsafe { self.state.ensure_stack(2)?; let _g = StackGuard::new(self.state); @@ -142,13 +142,22 @@ impl<'a> AnyUserdata<'a> { /// /// Will trigger a call to the `__index` metamethod. Use [`AnyUserdata::raw_get`] if you /// don't want to call it. - pub fn get(&'a self, key: K) -> crate::Result + pub fn get(&self, key: K) -> crate::Result where K: AsLua<'a>, V: FromLua<'a>, { let mt = self.get_metatable()?; - mt.get::(key) + let key = key.as_lua(self.state)?; + + if mt.has_key(key.clone())? { + mt.get::<_, V>(key) + } else if mt.has_key(MetaMethod::Index)? { + let index_fn: Function = mt.get(MetaMethod::Index)?; + index_fn.exec((self.as_lua(self.state)?, key,)) + } else { + Err(Error::Nil) + } } /// Gets something from the userdata. Will **not** trigger a call to the `__index` metamethod. diff --git a/src/userdata/builder.rs b/src/userdata/builder.rs index 121ab3c..9a4e586 100755 --- a/src/userdata/builder.rs +++ b/src/userdata/builder.rs @@ -35,7 +35,7 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> { pub fn field_getter(&mut self, name: &str, f: F) -> &mut Self where - F: Fn(&'a State, &T) -> crate::Result + 'static, + F: Fn(&'a State, &T) -> R + 'static, R: AsLua<'a>, T: Userdata + 'static { @@ -60,10 +60,10 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> { let this_ptr = this_ptr.cast::(); let this = unsafe { &*this_ptr }; - f(lua, this).and_then(|r| r.as_lua(lua)) + f(lua, this).as_lua(lua) } else { let this = this.as_ref::()?; - f(lua, &*this).and_then(|r| r.as_lua(lua)) + f(lua, &*this).as_lua(lua) } }; self.field_getters.insert(name.to_string(), Box::new(wrap)); diff --git a/src/value.rs b/src/value.rs index 41bb9af..c08d818 100755 --- a/src/value.rs +++ b/src/value.rs @@ -1,6 +1,6 @@ -use std::{collections::VecDeque, ffi::CStr, ops::{Deref, DerefMut}}; +use std::{cell::{Ref, RefMut}, collections::VecDeque, ffi::CStr, ops::{Deref, DerefMut}}; -use crate::{AnyUserdata, FromLuaStack, Function, PushToLuaStack, State, Table}; +use crate::{AnyUserdata, FromLuaStack, Function, Proxy, PushToLuaStack, State, Table, TableProxy, Userdata}; use mlua_sys as lua; @@ -132,6 +132,17 @@ impl<'a> Value<'a> { } } } + + /// If `self` is an instance of Value::Variadic, the ValueVec is returned. If it is not then + /// an `UnexpectedType` error is returned. + pub fn into_value_vec(self) -> crate::Result> { + match self { + Value::Variable(v) => Ok(v), + _ => { + Err(crate::Error::UnexpectedType("ValueVec".to_string(), self.type_name().to_string())) + } + } + } } impl<'a> PushToLuaStack<'a> for Value<'a> { @@ -229,6 +240,14 @@ pub trait AsLua<'a> { pub trait FromLua<'a>: Sized { fn from_lua(lua: &'a State, val: Value<'a>) -> crate::Result; + + /// Returns the amount of values this type takes. + /// + /// This is useful for function arguments where a type may take no values, or multiple. + /// Implementation of () have this set to 0 + fn value_size() -> usize { + 1 + } } impl<'a> AsLua<'a> for () { @@ -265,6 +284,10 @@ impl<'a> FromLua<'a> for () { fn from_lua(_lua: &'a State, _val: Value<'a>) -> crate::Result { Ok(()) } + + fn value_size() -> usize { + 0 + } } #[derive(Default, Clone)] @@ -284,6 +307,12 @@ impl<'a> DerefMut for ValueVec<'a> { } } +impl<'a> From>> for ValueVec<'a> { + fn from(value: VecDeque>) -> Self { + Self(value) + } +} + impl<'a> FromLuaStack<'a> for ValueVec<'a> { unsafe fn from_lua_stack(state: &'a State) -> crate::Result { let s = state.state_ptr(); @@ -314,6 +343,10 @@ impl<'a> ValueVec<'a> { vec } + + pub fn into_iter(self) -> std::collections::vec_deque::IntoIter> { + self.0.into_iter() + } } impl<'a> From> for ValueVec<'a> { @@ -372,10 +405,62 @@ impl<'a> PushToLuaStack<'a> for ValueVec<'a> { } } -impl<'a, T: FromLua<'a>> FromLuaVec<'a> for T { +/// A helper macro that implements FromLuaVec for a type that implements FromLua. +/// +/// This has to be done due to specialization, which is not stable in Rust. +macro_rules! impl_from_lua_vec_for_from_lua { + ($type: tt, 'a) => { + impl<'a> FromLuaVec<'a> for $type<'a> { + fn from_lua_value_vec(state: &'a State, mut values: ValueVec<'a>) -> crate::Result { + if let Some(val) = values.pop_front() { + Self::from_lua(state, val) + } else { + Err(crate::Error::IncorrectArgCount { + arg_expected: 1, + arg_count: values.len() as i32, + }) + } + } + } + }; + ($type: tt) => { + impl<'a> FromLuaVec<'a> for $type { + fn from_lua_value_vec(state: &'a State, mut values: ValueVec<'a>) -> crate::Result { + if let Some(val) = values.pop_front() { + $type::from_lua(state, val) + } else { + Err(crate::Error::IncorrectArgCount { + arg_expected: 1, + arg_count: values.len() as i32, + }) + } + } + } + }; +} + +impl_from_lua_vec_for_from_lua!(i64); +impl_from_lua_vec_for_from_lua!(u64); +impl_from_lua_vec_for_from_lua!(i16); +impl_from_lua_vec_for_from_lua!(u16); +impl_from_lua_vec_for_from_lua!(i8); +impl_from_lua_vec_for_from_lua!(u8); +impl_from_lua_vec_for_from_lua!(i32); +impl_from_lua_vec_for_from_lua!(u32); +impl_from_lua_vec_for_from_lua!(f64); +impl_from_lua_vec_for_from_lua!(f32); +impl_from_lua_vec_for_from_lua!(String); + +impl_from_lua_vec_for_from_lua!(Table, 'a); +impl_from_lua_vec_for_from_lua!(Value, 'a); +impl_from_lua_vec_for_from_lua!(Function, 'a); +impl_from_lua_vec_for_from_lua!(AnyUserdata, 'a); + + +impl<'a, T: Userdata + 'static> FromLuaVec<'a> for RefMut<'a, T> { fn from_lua_value_vec(state: &'a State, mut values: ValueVec<'a>) -> crate::Result { if let Some(val) = values.pop_front() { - T::from_lua(state, val) + Self::from_lua(state, val) } else { Err(crate::Error::IncorrectArgCount { arg_expected: 1, @@ -385,6 +470,45 @@ impl<'a, T: FromLua<'a>> FromLuaVec<'a> for T { } } +impl<'a, T: Userdata + 'static> FromLuaVec<'a> for Ref<'a, T> { + fn from_lua_value_vec(state: &'a State, mut values: ValueVec<'a>) -> crate::Result { + if let Some(val) = values.pop_front() { + Self::from_lua(state, val) + } else { + Err(crate::Error::IncorrectArgCount { + arg_expected: 1, + arg_count: values.len() as i32, + }) + } + } +} + +impl<'a, T: TableProxy> FromLuaVec<'a> for Proxy { + fn from_lua_value_vec(state: &'a State, mut values: ValueVec<'a>) -> crate::Result { + if let Some(val) = values.pop_front() { + Self::from_lua(state, val) + } else { + Err(crate::Error::IncorrectArgCount { + arg_expected: 1, + arg_count: values.len() as i32, + }) + } + } +} + +impl<'a> FromLuaVec<'a> for () { + fn from_lua_value_vec(_: &'a State, values: ValueVec<'a>) -> crate::Result { + if values.is_empty() { + Ok(()) + } else { + Err(crate::Error::IncorrectArgCount { + arg_expected: 0, + arg_count: values.len() as i32, + }) + } + } +} + impl<'a> IntoLuaVec<'a> for () { fn into_lua_value_vec(self, _state: &'a State) -> crate::Result> { Ok(ValueVec::new()) diff --git a/src/variadic.rs b/src/variadic.rs new file mode 100644 index 0000000..1b76f82 --- /dev/null +++ b/src/variadic.rs @@ -0,0 +1,63 @@ +use std::{collections::{vec_deque, VecDeque}, marker::PhantomData, ops::{Deref, DerefMut}}; + +use crate::{AsLua, Error, FromLua, FromLuaVec, Value, ValueVec}; + +pub struct Variadic<'a, T: FromLua<'a> + AsLua<'a>>(VecDeque, PhantomData<&'a T>); + +impl<'a, T: FromLua<'a> + AsLua<'a>> Variadic<'a, T> { + pub fn into_iter(self) -> vec_deque::IntoIter { + self.0.into_iter() + } +} + +impl<'a, T: FromLua<'a> + AsLua<'a>> Deref for Variadic<'a, T> { + type Target = VecDeque; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a, T: FromLua<'a> + AsLua<'a>> DerefMut for Variadic<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl<'a, T: FromLua<'a> + AsLua<'a>> FromLua<'a> for Variadic<'a, T> { + fn from_lua(lua: &'a crate::State, val: crate::Value<'a>) -> crate::Result { + let mut vec = VecDeque::new(); + let vals = val.into_value_vec()?; + + for val in vals.into_iter() { + vec.push_back( + T::from_lua(lua, val) + .map_err(|e| match e { + Error::UnexpectedType(ty, ret) => { + let ty = format!("Variadic<{}>", ty); + let ret = format!("ran into {}", ret); + + Error::UnexpectedType(ty, ret) + }, + _ => e, + })? + ); + } + + Ok(Self(vec, PhantomData)) + } +} + +impl<'a, T: FromLua<'a> + AsLua<'a>> AsLua<'a> for Variadic<'a, T> { + fn as_lua(&self, lua: &'a crate::State) -> crate::Result> { + let v: Result, _> = self.0.iter().map(|v| v.as_lua(lua)).collect(); + Value::Variable(ValueVec::from(v?)) + .as_lua(lua) + } +} + +impl<'a, T: FromLua<'a> + AsLua<'a>> FromLuaVec<'a> for Variadic<'a, T> { + fn from_lua_value_vec(state: &'a crate::State, values: crate::ValueVec<'a>) -> crate::Result { + Variadic::from_lua(state, Value::Variable(values)) + } +} \ No newline at end of file