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