From 35bd889b4829446f972292440174e7c0e4fa40a2 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Sat, 17 Feb 2024 14:24:58 -0500 Subject: [PATCH] Fix lots of bugs, add thread placeholder type, fix ValueVec when used in tuples, much more --- src/chunk.rs | 31 ++++- src/error.rs | 21 +++- src/function.rs | 30 +++-- src/guard.rs | 6 +- src/lib.rs | 19 +-- src/lref.rs | 13 +- src/state.rs | 234 ++++++++++++++++++++++++++++------- src/table.rs | 25 ++-- src/thread.rs | 16 +++ src/userdata/any.rs | 40 ++++-- src/userdata/mod.rs | 9 +- src/userdata/proxy.rs | 6 - src/util.rs | 2 +- src/value.rs | 280 +++++++++++++++++++++++++++++------------- src/variadic.rs | 55 ++++++--- 15 files changed, 589 insertions(+), 198 deletions(-) create mode 100644 src/thread.rs diff --git a/src/chunk.rs b/src/chunk.rs index a247f79..d85323b 100755 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -1,6 +1,6 @@ use std::borrow::{Borrow, Cow}; -use crate::{FromLua, Function, IntoLuaVec, State}; +use crate::{FromLua, FromLuaVec, Function, IntoLuaVec, State}; pub struct Chunk<'a> { state: &'a State, @@ -39,7 +39,7 @@ impl<'a> Chunk<'a> { pub fn execute(&'a self, args: A) -> crate::Result where A: IntoLuaVec<'a>, - R: FromLua<'a> + R: FromLuaVec<'a> { self.state.execute_chunk::(self, args) } @@ -66,24 +66,43 @@ pub trait IntoChunkData<'a> { impl<'a> IntoChunkData<'a> for &'a str { fn into_chunk(self) -> Cow<'a, [u8]> { - Cow::Borrowed(self.as_bytes()) + if self.ends_with("\n") { + Cow::Borrowed(self.as_bytes()) + } else { + let s = format!("{}\n", self); + Cow::Owned(s.as_bytes().to_vec()) + } } } impl<'a> IntoChunkData<'a> for &'a String { fn into_chunk(self) -> Cow<'a, [u8]> { - Cow::Borrowed(self.as_bytes()) + let s = format!("{}\n", self); + Cow::Owned(s.as_bytes().to_vec()) } } impl<'a> IntoChunkData<'a> for String { fn into_chunk(self) -> Cow<'a, [u8]> { - Cow::Owned(self.as_bytes().to_vec()) + let s = if self.ends_with("\n") { + self + } else { + format!("{self}\n") + }; + + Cow::Owned(s.as_bytes().to_vec()) } } impl<'a> IntoChunkData<'a> for &'a [u8] { fn into_chunk(self) -> Cow<'a, [u8]> { - Cow::Borrowed(self) + if self.ends_with("\n".as_bytes()) { + Cow::Borrowed(self) + } else { + let mut v = self.to_vec(); + v.extend_from_slice("\n".as_bytes()); + + Cow::Owned(v) + } } } \ No newline at end of file diff --git a/src/error.rs b/src/error.rs index c6a0260..e98b157 100755 --- a/src/error.rs +++ b/src/error.rs @@ -16,8 +16,11 @@ pub enum Error { MemoryAlloc, #[error("Ran into a nill value on the stack")] Nil, - #[error("Unexpected type, expected {0} but got {1}")] - UnexpectedType(String, String), + #[error("Type mismatch, expected {expected} but got {got}")] + TypeMismatch { + expected: String, + got: String, + }, #[error("bad argument #{arg_index}{} to `{}` ({error})", .arg_name.clone().map(|a| format!(" (name: {})", a)).unwrap_or("".to_string()), .func.clone().unwrap_or("Unknown".to_string()) @@ -47,6 +50,8 @@ pub enum Error { #[source] error: Arc, }, + #[error("{0}")] + Other(Arc), } impl Error { @@ -54,8 +59,11 @@ impl Error { Self::Runtime(msg.to_string()) } - pub fn unexpected_type(expected: &str, got: &str) -> Self { - Self::UnexpectedType(expected.to_string(), got.to_string()) + pub fn type_mismatch>(expected: S, got: S) -> Self { + Self::TypeMismatch { + expected: expected.as_ref().to_string(), + got: got.as_ref().to_string(), + } } /// Throw the error in lua. @@ -67,6 +75,11 @@ impl Error { lua::luaL_error(lua, msg_c); unreachable!(); } + + /// Create a `Error::other` from an unknown error type + pub fn other(e: T) -> Self { + Self::Other(Arc::new(e)) + } } /// A result for use with lua functions diff --git a/src/function.rs b/src/function.rs index 143aa84..78dc086 100755 --- a/src/function.rs +++ b/src/function.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use crate::{AsLua, FromLua, FromLuaStack, IntoLuaVec, LuaRef, PushToLuaStack, StackGuard, State, Value, ValueVec}; +use crate::{AsLua, Error, FromLua, FromLuaStack, FromLuaVec, IntoLuaVec, LuaRef, PushToLuaStack, StackGuard, State, Value, ValueVec}; use mlua_sys as lua; @@ -39,7 +39,7 @@ impl<'a> Function<'a> { pub fn exec(&self, args: A) -> crate::Result where A: IntoLuaVec<'a>, - R: FromLua<'a>, + R: FromLuaVec<'a>, { unsafe { let _g = StackGuard::new(self.state); @@ -61,7 +61,11 @@ impl<'a> Function<'a> { self.push_to_lua_stack(self.state)?; args_val.push_to_lua_stack(self.state)?; - match lua::lua_pcall(s, args_len, lua::LUA_MULTRET, handler_idx) { + State::print_stack(self.state); + + let val_count = R::value_num().unwrap_or(lua::LUA_MULTRET as usize); + + match lua::lua_pcall(s, args_len, val_count as i32, handler_idx) { lua::LUA_ERRRUN => { let er = self.state.get_error_str(); return Err(crate::Error::runtime(er)); @@ -76,30 +80,40 @@ impl<'a> Function<'a> { }, _ => {} } + + State::print_stack(self.state); - let ret_count = lua::lua_gettop(s); + /* let ret_count = lua::lua_gettop(s); let val = if ret_count > 1 { let vals = ValueVec::from_lua_stack(self.state)?; - Value::Variable(vals) + Value::Multi(vals) } else if ret_count == 1 { Value::from_lua_stack(self.state)? } else { Value::None + }; */ + + let vals = if R::value_num().is_some() { + ValueVec::from_stack_limit(self.state, val_count)? + } else { + ValueVec::from_lua_stack(self.state)? }; - R::from_lua(self.state, val) + R::from_lua_value_vec(self.state, vals) } } } impl<'a> AsLua<'a> for Function<'a> { - fn as_lua(&self, _lua: &'a State) -> crate::Result> { - Ok(crate::Value::Function(self.clone())) + fn as_lua(self, _lua: &'a State) -> crate::Result> { + Ok(crate::Value::Function(self)) } } impl<'a> FromLua<'a> for Function<'a> { fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result { + let tyname = val.type_name(); val.into_function() + .ok_or(Error::type_mismatch("Function", &tyname)) } } \ No newline at end of file diff --git a/src/guard.rs b/src/guard.rs index 291bbf4..b609e8a 100755 --- a/src/guard.rs +++ b/src/guard.rs @@ -35,11 +35,11 @@ impl<'a> StackGuard<'a> { } } -pub unsafe fn lua_error_guard(lua: &State, func: F) -> R +pub unsafe fn lua_error_guard<'a, F, R>(lua: &'a State, func: F) -> R where - F: Fn() -> crate::Result + F: Fn(&'a State) -> crate::Result { - match func() { + match func(lua) { Ok(v) => v, Err(e) => e.throw_lua(lua.state_ptr()) } diff --git a/src/lib.rs b/src/lib.rs index c737bb4..ca6aba4 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,10 @@ pub mod guard; pub use guard::*; pub mod userdata; -use userdata::*; +pub use userdata::*; + +pub mod thread; +pub use thread::*; pub mod util; #[allow(unused_imports)] @@ -69,8 +72,8 @@ impl<'a, T: PushToLuaStack<'a>> PushToLuaStack<'a> for Option { macro_rules! impl_as_lua_number { ($ty: ident) => { impl<'a> AsLua<'a> for $ty { - fn as_lua(&self, _lua: &'a State) -> crate::Result> { - Ok(Value::Number(*self as f64)) + fn as_lua(self, _lua: &'a State) -> crate::Result> { + Ok(Value::Number(self as f64)) } } @@ -78,9 +81,9 @@ macro_rules! impl_as_lua_number { fn from_lua(_lua: &State, val: Value) -> crate::Result { match val { Value::Number(v) => Ok(v as $ty), - _ => Err(Error::UnexpectedType( - "Number".to_string(), - val.type_name().to_string(), + _ => Err(Error::type_mismatch( + "Number", + &val.type_name(), )), } } @@ -121,7 +124,9 @@ impl<'a> PushToLuaStack<'a> for String { impl<'a> FromLua<'a> for String { fn from_lua(_lua: &State, val: Value) -> crate::Result { - val.as_string().cloned() + Ok(val.as_string() + .ok_or(Error::type_mismatch("String", &val.type_name()))? + .clone()) } } diff --git a/src/lref.rs b/src/lref.rs index 65abdb6..efa11ae 100755 --- a/src/lref.rs +++ b/src/lref.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use crate::{Error, PushToLuaStack, Result, State}; +use crate::{Error, PushToLuaStack, Result, StackGuard, State}; use mlua_sys as lua; @@ -18,9 +18,8 @@ pub struct LuaRef<'a> { impl<'a> Drop for LuaRef<'a> { fn drop(&mut self) { unsafe { - let s = self.state.state_ptr(); - if Arc::strong_count(&self.lref) == 1 { + let s = self.state.state_ptr(); lua::luaL_unref(s, lua::LUA_REGISTRYINDEX, *self.lref); } } @@ -50,13 +49,19 @@ impl<'a> LuaRef<'a> { impl<'a> PushToLuaStack<'a> for LuaRef<'a> { unsafe fn push_to_lua_stack(&self, state: &State) -> Result<()> { let s = state.state_ptr(); - state.ensure_stack(1)?; + let top = lua::lua_gettop(s); let ty = lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, *self.lref as i64); let new_top = lua::lua_gettop(s); + // make sure that the ref was actually made if ty == lua::LUA_TNIL || ty == lua::LUA_TNONE || top == new_top { + // nil may have been pushed to the stack, remove it + if new_top > top { + lua::lua_pop(s, 1); + } + return Err(Error::Nil); } diff --git a/src/state.rs b/src/state.rs index c390506..a73949a 100755 --- a/src/state.rs +++ b/src/state.rs @@ -1,7 +1,7 @@ use core::ffi; use std::{alloc::{self, Layout}, any::TypeId, cell::RefCell, collections::HashMap, ffi::{CStr, CString}, mem, ptr::{self, NonNull}, str::Utf8Error, sync::Arc}; -use lua::lua_gc; +use lua::{lua_State, lua_gc}; use mlua_sys as lua; use crate::{lua_error_guard, proxy::UserdataProxy, AnyUserdata, AsLua, Chunk, Error, FromLua, FromLuaStack, FromLuaVec, Function, IntoChunkData, IntoLuaVec, LuaRef, MetaMethod, PushToLuaStack, Result, StackGuard, Table, Userdata, UserdataBuilder, Value, ValueVec}; @@ -65,8 +65,21 @@ impl StdLibraries { Self::default() } + /// A helper function that returns an instance that contains all libraries pub fn all() -> Self { - todo!() + let mut v = Self::new(); + let libs = &mut v.libs; + libs.push(StdLibrary::Coroutine); + libs.push(StdLibrary::Table); + libs.push(StdLibrary::Io); + libs.push(StdLibrary::Os); + libs.push(StdLibrary::String); + libs.push(StdLibrary::Utf8); + libs.push(StdLibrary::Math); + libs.push(StdLibrary::Debug); + libs.push(StdLibrary::Package); + + v } pub fn load(&mut self, lib: StdLibrary) { @@ -85,64 +98,110 @@ impl From<&[StdLibrary; N]> for StdLibraries { /// A struct that is used as an upvalue for creating Lua callable functions struct ClosureData<'a> { wrapper_fn: Box i32>, - state: &'a State, + state: NonNull, } -#[derive(Default)] +//#[derive(Default)] pub struct ExtraSpace<'a> { pub userdata_metatables: HashMap>, + pub state_ptr: StatePtr +} + +impl<'a> ExtraSpace<'a> { + pub fn new(state: &State) -> Self { + Self { + userdata_metatables: Default::default(), + state_ptr: state.ptr.clone() + } + } +} + +#[derive(Clone)] +pub struct StatePtr { + lua: Arc>, } pub struct State { - lua: NonNull, + ptr: StatePtr, +} + +impl Default for State { + fn default() -> Self { + Self::new() + } } impl Drop for State { fn drop(&mut self) { unsafe { - let extra = self.get_extra_space_ptr(); - - { - // clear the refs to anything in lua before we close it and - // attempt to drop extra after - let extra = &mut *extra; - extra.userdata_metatables.clear(); + println!("State count: {}", Arc::strong_count(&self.ptr.lua)); + if Arc::strong_count(&self.ptr.lua) == 2 { // this owned arc, and the one in extra + let extra = self.get_extra_space_ptr(); + + { + // clear the refs to anything in lua before we close it and + // attempt to drop extra after + let extra = &mut *extra; + extra.userdata_metatables.clear(); + } + + lua::lua_close(self.state_ptr()); + extra.drop_in_place(); + + // must be dealloced since it wasn't memory created from lua (i.e. userdata) + alloc::dealloc(extra.cast(), Layout::new::()); } - - lua::lua_close(self.lua.as_ptr()); - extra.drop_in_place(); - - // must be dealloced since it wasn't memory created from lua (i.e. userdata) - alloc::dealloc(extra.cast(), Layout::new::()); } } } +unsafe fn extra_space<'a>(state: *mut lua::lua_State) -> *mut ExtraSpace<'a> { + let extra = lua::lua_getextraspace(state) + .cast::<*mut ExtraSpace>(); + *extra +} + impl State { pub fn new() -> Self { let s = Self { - lua: unsafe { NonNull::new_unchecked(lua::luaL_newstate()) } + ptr: StatePtr { + lua: Arc::new(unsafe { NonNull::new_unchecked(lua::luaL_newstate()) }) + } }; s.alloc_extra_space(); s } + /// Creates a new Lua State, exposes the provides libraries in the state + pub fn new_with_libraries>(libs: L) -> Self { + let s = Self::new(); + + s.expose_libraries(libs); + s + } + pub fn from_ptr(lua: *mut lua::lua_State) -> Self { - Self { - lua: unsafe { NonNull::new_unchecked(lua) } + unsafe { + let extra = lua::lua_getextraspace(lua) + .cast::<*mut ExtraSpace>(); + let extra = *extra; + + Self { + ptr: (*extra).state_ptr.clone() + } } } pub(crate) fn state_ptr(&self) -> *mut lua::lua_State { - self.lua.as_ptr() + self.ptr.lua.as_ptr() } fn alloc_extra_space(&self) { unsafe { let extra_ptr = alloc::alloc(Layout::new::()) .cast::(); - ptr::write(extra_ptr, ExtraSpace::default()); + ptr::write(extra_ptr, ExtraSpace::new(self)); let s = self.state_ptr(); let loc = lua::lua_getextraspace(s); @@ -192,7 +251,7 @@ impl State { unsafe { self.ensure_stack(1)?; let _g = StackGuard::new(self); - let s = self.lua.as_ptr(); + let s = self.state_ptr(); let chunk_data = chunk.into_chunk(); let chunk_ptr = chunk_data.as_ptr().cast(); @@ -221,7 +280,7 @@ impl State { pub fn execute_chunk<'a, A, R>(&'a self, chunk: &'a Chunk, args: A) -> Result where A: IntoLuaVec<'a>, - R: FromLua<'a> + R: FromLuaVec<'a> { let handler = self.create_function(|lua, msg: String| { lua.state_error_handler(msg) @@ -234,7 +293,7 @@ impl State { } pub fn expose_libraries>(&self, libs: L) { - let lua = self.lua.as_ptr(); + let lua = self.state_ptr(); unsafe { let base = "_G\0".as_ptr().cast(); @@ -311,7 +370,7 @@ impl State { pub fn create_function<'a, A, R, F>(&self, f: F) -> Result where A: FromLuaVec<'a>, - R: AsLua<'a>, //PushToLuaStackMulti<'a>, + R: AsLua<'a>, F: Fn(&'a State, A) -> Result + 'static, { unsafe extern "C-unwind" fn rust_closure(s: *mut lua::lua_State) -> i32 { @@ -331,9 +390,11 @@ impl State { let top = lua::lua_gettop(s); let wrap = &(*data_ptr).wrapper_fn; - let s = (*data_ptr).state; - wrap(s, top) + let extra = extra_space(s); + let lua: &State = mem::transmute(&(*extra).state_ptr.lua); + + wrap(lua, top) }, _ => { let name = CStr::from_ptr(lua::lua_typename(s, ltype)); @@ -349,25 +410,23 @@ impl State { } } - let wrapper_fn = move |lua: &State, _narg: i32| -> i32 { + let wrapper_fn = move |lua: &'a State, _narg: i32| -> i32 { unsafe { - let lua: &State = mem::transmute(lua); // transmute lifetimes + lua_error_guard(lua, |lua| { + let vec = ValueVec::from_lua_stack(lua).unwrap(); - lua_error_guard(lua, || { - let vec = ValueVec::from_lua_stack(lua)?; + let args = A::from_lua_value_vec(lua, vec).unwrap(); - let args = A::from_lua_value_vec(lua, vec)?; - - let r = f(lua, args)?; - let r_val = r.as_lua(lua)?; + let r = f(lua, args).unwrap(); + let r_val = r.as_lua(lua).unwrap(); let args_len = match &r_val { - Value::Variable(v) => v.len(), + Value::Multi(v) => v.len(), Value::None => 0, _ => 1, } as _; - r_val.push_to_lua_stack(lua)?; + r_val.push_to_lua_stack(lua).unwrap(); Ok(args_len) }) @@ -376,12 +435,15 @@ impl State { let data = ClosureData { wrapper_fn: Box::new(wrapper_fn), - state: self, + state: NonNull::from(self), }; let s = self.state_ptr(); unsafe { + let _g = StackGuard::new(self); + self.ensure_stack(3)?; + let ptr = lua::lua_newuserdata(s, mem::size_of::()); let ptr = ptr.cast(); ptr::write(ptr, data); @@ -583,7 +645,9 @@ impl State { } let v = Value::from_lua_stack(self)?; - let s = v.into_string()?; + let tyname = v.type_name(); + let s = v.into_string() + .ok_or(Error::type_mismatch("String", &tyname))?; Ok(s) } } @@ -686,9 +750,95 @@ impl State { } } } + + /// Inserts a value into the [Lua Registry](https://www.lua.org/manual/5.4/manual.html#4.3), + /// returning a key that can be used with [`State::registry_get`] to retrieve it. + pub fn registry_insert<'a, T: AsLua<'a>>(&'a self, val: T) -> Result { + let val = val.as_lua(self)?; + unsafe { + val.push_to_lua_stack(self)?; + + let s = self.state_ptr(); + let r = lua::luaL_ref(s, lua::LUA_REGISTRYINDEX); + if r == lua::LUA_REFNIL { + Err(Error::Nil) + } else { + Ok(RegistryKey(r)) + } + } + } + + /// Retrieves a value from the [Lua Registry](https://www.lua.org/manual/5.4/manual.html#4.3) + /// however, this does not remove it from the registry. See [`State::registry_remove`] for that. + pub fn registry_get<'a, T: FromLua<'a>>(&'a self, key: RegistryKey) -> Result { + unsafe { + let _g = StackGuard::new(self); + let s = self.state_ptr(); + self.ensure_stack(1)?; + + let top = lua::lua_gettop(s); + let ty = lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, key.0 as i64); + let new_top = lua::lua_gettop(s); + + // make sure that the ref was actually made + if ty == lua::LUA_TNIL || ty == lua::LUA_TNONE || top == new_top { + return Err(Error::Nil); + } + + let val = Value::from_lua_stack(self)?; + T::from_lua(self, val) + } + } + + /// Returns a boolean indicating if the [Lua Registry](https://www.lua.org/manual/5.4/manual.html#4.3) + /// contains a value at the provided key. + pub fn registry_contains(&self, key: RegistryKey) -> Result { + unsafe { + let _g = StackGuard::new(self); + let s = self.state_ptr(); + self.ensure_stack(1)?; + + let top = lua::lua_gettop(s); + let ty = lua::lua_rawgeti(s, lua::LUA_REGISTRYINDEX, key.0 as i64); + let new_top = lua::lua_gettop(s); + + // make sure that the ref was actually made + if ty == lua::LUA_TNIL || ty == lua::LUA_TNONE || top == new_top { + Ok(false) + } else { + Ok(true) + } + } + } + + /// Removes a value from the [Lua Registry](https://www.lua.org/manual/5.4/manual.html#4.3) + /// at the provided key. Returns a boolean indicating if anything was removed. + /// + /// > Note: This does not call for garbage collection of the removed value. For that you + /// must use [`State::gc_collect`]. + pub fn registry_remove(&self, key: RegistryKey) -> Result { + unsafe { + if self.registry_contains(key)? { + let s = self.state_ptr(); + lua::luaL_unref(s, lua::LUA_REGISTRYINDEX, key.0); + + Ok(true) + } else { + Ok(false) + } + } + } } pub enum GcMode { Incremental, Generational, -} \ No newline at end of file +} + +/// A struct used to represent an entry in the +/// [Lua Registry](https://www.lua.org/manual/5.4/manual.html#4.3). +// +// A LuaRef would work just as well, but this is lighter without an Arc, and without a +// reference to the state. +#[derive(Clone, Copy)] +pub struct RegistryKey(i32); \ No newline at end of file diff --git a/src/table.rs b/src/table.rs index 99fd433..758afab 100755 --- a/src/table.rs +++ b/src/table.rs @@ -1,6 +1,6 @@ use mlua_sys as lua; -use crate::{ensure_type, AsLua, FromLua, FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuard, State, Value}; +use crate::{ensure_type, AsLua, Error, FromLua, FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuard, State, Value}; #[derive(Clone)] pub struct Table<'a> { @@ -38,8 +38,8 @@ impl<'a> Table<'a> { let s = state.state_ptr(); if lua::luaL_newmetatable(s, name_term_c) == 0 { - // lua::luaL_getmetatable does not return the type that was - // retrieved from the registry + // if no table was pushed, there is a registry conflict, so try to get the table + // from the registry lua::lua_pushstring(s, name_term_c); let ty = lua::lua_rawget(s, lua::LUA_REGISTRYINDEX); @@ -47,6 +47,7 @@ impl<'a> Table<'a> { return Err(crate::Error::RegistryConflict(name.to_string())); } } + LuaRef::from_stack(state)? }; @@ -306,13 +307,15 @@ impl<'a> FromLuaStack<'a> for Table<'a> { impl<'a> FromLua<'a> for Table<'a> { fn from_lua(_: &'a State, val: Value<'a>) -> crate::Result { + let tyname = val.type_name(); val.into_table() + .ok_or(Error::type_mismatch("Table", &tyname)) } } impl<'a> AsLua<'a> for Table<'a> { - fn as_lua(&self, _: &'a State) -> crate::Result> { - Ok(Value::Table(self.clone())) + fn as_lua(self, _: &'a State) -> crate::Result> { + Ok(Value::Table(self)) } } @@ -322,6 +325,8 @@ impl<'a> AsLua<'a> for Table<'a> { /// also retrieve an instance of your Rust type from an instance of the Lua type. This could help /// with minimizing the amount of calls to and from Rust. pub trait TableProxy: Sized { + /// Returns the name of the table + fn table_name() -> String; /// Create an instance of `Self` from the table fn from_table<'a>(lua: &'a State, table: Table<'a>) -> Result; /// Creates a Lua instance from `Self` @@ -365,7 +370,9 @@ impl From for Proxy { // getting a borrow. impl<'a, T: TableProxy> FromLua<'a> for Proxy { fn from_lua(lua: &'a State, val: Value<'a>) -> crate::Result { - let table = val.into_table()?; + let tyname = val.type_name(); + let table = val.into_table() + .ok_or(Error::type_mismatch("Table", &tyname))?; let t = T::from_table(lua, table)?; Ok(Self::from(t)) @@ -373,7 +380,7 @@ impl<'a, T: TableProxy> FromLua<'a> for Proxy { } impl<'a, T: TableProxy> AsLua<'a> for Proxy { - fn as_lua(&self, lua: &'a State) -> crate::Result> { + fn as_lua(self, lua: &'a State) -> crate::Result> { self.data.as_ref() .ok_or(crate::Error::Nil) .and_then(|d| d.as_table(lua)) @@ -402,6 +409,10 @@ mod tests { let new_fn: Function = vec2.get("new")?; new_fn.exec((vec2, self.x, self.y)) } + + fn table_name() -> String { + "Vec2".to_string() + } } #[test] diff --git a/src/thread.rs b/src/thread.rs new file mode 100644 index 0000000..319c381 --- /dev/null +++ b/src/thread.rs @@ -0,0 +1,16 @@ +use crate::{FromLuaStack, LuaRef, PushToLuaStack}; + +#[derive(Clone)] +pub struct LuaThread<'a>(LuaRef<'a>); + +impl<'a> PushToLuaStack<'a> for LuaThread<'a> { + unsafe fn push_to_lua_stack(&self, state: &'a crate::State) -> crate::Result<()> { + self.0.push_to_lua_stack(state) + } +} + +impl<'a> FromLuaStack<'a> for LuaThread<'a> { + unsafe fn from_lua_stack(state: &'a crate::State) -> crate::Result { + Ok(Self(LuaRef::from_stack(state)?)) + } +} \ No newline at end of file diff --git a/src/userdata/any.rs b/src/userdata/any.rs index 37bc920..430bd3e 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, Error, FromLua, FromLuaStack, Function, IntoLuaVec, LuaRef, MetaMethod, PushToLuaStack, StackGuard, State, Table, Userdata, Value}; +use crate::{ensure_type, AsLua, Error, FromLua, FromLuaStack, FromLuaVec, Function, IntoLuaVec, LuaRef, MetaMethod, PushToLuaStack, StackGuard, State, Table, Userdata, Value}; /// A handle to some userdata on the stack //#[derive(Clone)] @@ -145,7 +145,7 @@ impl<'a> AnyUserdata<'a> { pub fn get(&self, key: K) -> crate::Result where K: AsLua<'a>, - V: FromLua<'a>, + V: FromLuaVec<'a> + FromLua<'a>, { let mt = self.get_metatable()?; let key = key.as_lua(self.state)?; @@ -154,7 +154,7 @@ impl<'a> AnyUserdata<'a> { 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,)) + index_fn.exec((self.clone().as_lua(self.state)?, key,)) } else { Err(Error::Nil) } @@ -175,7 +175,7 @@ impl<'a> AnyUserdata<'a> { pub fn execute_method(&'a self, name: &str, args: A) -> crate::Result where A: IntoLuaVec<'a>, - R: FromLua<'a>, + R: FromLuaVec<'a> + FromLua<'a>, { let name = name.to_string(); let mt = self.get_metatable()?; @@ -186,6 +186,22 @@ impl<'a> AnyUserdata<'a> { f.exec(args) } + + /// Execute a function on this userdata. + /// + /// This searches for a function with `name` and executes it. This may cause an execution + /// of the `__index` meta method. + pub fn execute_function(&'a self, name: &str, args: A) -> crate::Result + where + A: IntoLuaVec<'a>, + R: FromLuaVec<'a> + FromLua<'a>, + { + let name = name.to_string(); + let mt = self.get_metatable()?; + let f = mt.get::<_, Function>(name)?; + + f.exec(args) + } } impl<'a> FromLuaStack<'a> for AnyUserdata<'a> { @@ -206,27 +222,33 @@ impl<'a> PushToLuaStack<'a> for AnyUserdata<'a> { } impl<'a> AsLua<'a> for AnyUserdata<'a> { - fn as_lua(&self, _lua: &'a State) -> crate::Result> { - Ok(Value::Userdata(self.clone())) + fn as_lua(self, _lua: &'a State) -> crate::Result> { + Ok(Value::Userdata(self)) } } impl<'a> FromLua<'a> for AnyUserdata<'a> { - fn from_lua(_lua: &State, val: Value<'a>) -> crate::Result { + fn from_lua(_: &State, val: Value<'a>) -> crate::Result { + let tyname = val.type_name(); val.into_userdata() + .ok_or(Error::type_mismatch("Userdata", &tyname)) } } impl<'a, T: Userdata + 'static> FromLua<'a> for Ref<'a, T> { fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result { - let ud = val.into_userdata()?; + let tyname = val.type_name(); + let ud = val.into_userdata() + .ok_or(Error::type_mismatch("Userdata", &tyname))?; ud.as_ref::() } } impl<'a, T: Userdata + 'static> FromLua<'a> for RefMut<'a, T> { fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result { - let ud = val.into_userdata()?; + let tyname = val.type_name(); + let ud = val.into_userdata() + .ok_or(Error::type_mismatch("Userdata", &tyname))?; ud.as_mut::() } } \ No newline at end of file diff --git a/src/userdata/mod.rs b/src/userdata/mod.rs index 7e20bea..30e33e9 100755 --- a/src/userdata/mod.rs +++ b/src/userdata/mod.rs @@ -90,7 +90,7 @@ impl AsRef for MetaMethod { } impl<'a> AsLua<'a> for MetaMethod { - fn as_lua(&self, _lua: &'a State) -> crate::Result> { + fn as_lua(self, _lua: &'a State) -> crate::Result> { let s = self.as_ref(); Ok(Value::String(s.to_string())) @@ -108,4 +108,11 @@ pub trait Userdata: Sized { fn name() -> String; fn build<'a>(state: &State, builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()>; +} + +impl<'a, T: Userdata + 'static> AsLua<'a> for T { + fn as_lua(self, lua: &'a State) -> crate::Result> { + lua.create_userdata(self) + .and_then(|v| v.as_lua(lua)) + } } \ No newline at end of file diff --git a/src/userdata/proxy.rs b/src/userdata/proxy.rs index 7e9611f..69a5b70 100755 --- a/src/userdata/proxy.rs +++ b/src/userdata/proxy.rs @@ -10,12 +10,6 @@ impl UserdataProxy { } } -impl<'a, T: Userdata> AsLua<'a> for UserdataProxy { - fn as_lua(&self, _lua: &'a State) -> crate::Result> { - todo!() - } -} - impl Userdata for UserdataProxy { fn build<'a>(state: &State, builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()> { let mut other = UserdataBuilder::::new(); diff --git a/src/util.rs b/src/util.rs index 0be8fde..0a7d27f 100755 --- a/src/util.rs +++ b/src/util.rs @@ -22,7 +22,7 @@ pub(crate) unsafe fn ensure_type(state: &State, typ: i32, idx: i32) -> crate::Re let s = cstr.to_str() .expect("Lua type has invalid bytes!"); - Err(crate::Error::UnexpectedType(exp_s.to_string(), s.to_string())) + Err(crate::Error::type_mismatch(exp_s, s)) } } diff --git a/src/value.rs b/src/value.rs index c08d818..f955e78 100755 --- a/src/value.rs +++ b/src/value.rs @@ -1,6 +1,6 @@ use std::{cell::{Ref, RefMut}, collections::VecDeque, ffi::CStr, ops::{Deref, DerefMut}}; -use crate::{AnyUserdata, FromLuaStack, Function, Proxy, PushToLuaStack, State, Table, TableProxy, Userdata}; +use crate::{AnyUserdata, Error, FromLuaStack, Function, LuaThread, Proxy, PushToLuaStack, State, Table, TableProxy, Userdata}; use mlua_sys as lua; @@ -10,12 +10,14 @@ pub enum Value<'a> { /// This is different than Nil, which does get pushed to the stack. None, Nil, + Boolean(bool), Number(f64), String(String), Function(Function<'a>), + Thread(LuaThread<'a>), Table(Table<'a>), Userdata(AnyUserdata<'a>), - Variable(ValueVec<'a>), + Multi(ValueVec<'a>), } impl<'a> Value<'a> { @@ -23,124 +25,110 @@ impl<'a> Value<'a> { matches!(self, Value::Nil) } + pub fn is_none(&self) -> bool { + matches!(self, Value::None) + } + pub fn type_name(&self) -> String { match self { Value::None => "None".to_string(), Value::Nil => "Nil".to_string(), + Value::Boolean(_) => "Boolean".to_string(), Value::Number(_) => "Number".to_string(), Value::String(_) => "String".to_string(), Value::Function(_) => "Function".to_string(), + Value::Thread(_) => "Thread".to_string(), Value::Table(_) => "Table".to_string(), Value::Userdata(ud) => ud.name().unwrap(), - Value::Variable(_) => todo!(), + Value::Multi(_) => "Multi".to_string(), } } - pub fn as_number(&self) -> crate::Result { + pub fn as_number(&self) -> Option { match self { - Value::Number(v) => Ok(*v), - _ => { - Err(crate::Error::UnexpectedType("Number".to_string(), self.type_name().to_string())) - } + Value::Number(v) => Some(*v), + _ => None } } /// If `self` is an instance of Value::String, returns a borrow to it. If it is not then /// an `UnexpectedType` error is returned. - pub fn as_string(&self) -> crate::Result<&String> { + pub fn as_string(&self) -> Option<&String> { match self { - Value::String(s) => Ok(s), - _ => { - Err(crate::Error::UnexpectedType("String".to_string(), self.type_name().to_string())) - } + Value::String(s) => Some(s), + _ => None } } /// If `self` is an instance of Value::Function, returns a borrow to it. If it is not then /// an `UnexpectedType` error is returned. - pub fn as_function(&self) -> crate::Result { + pub fn as_function(&self) -> Option<&Function> { match self { - Value::Function(v) => Ok(v.clone()), - _ => { - Err(crate::Error::UnexpectedType("Table".to_string(), self.type_name().to_string())) - } + Value::Function(v) => Some(v), + _ => None, } } /// If `self` is an instance of Value::Table, returns a borrow to it. If it is not then /// an `UnexpectedType` error is returned. - pub fn as_table(&self) -> crate::Result { + pub fn as_table(&self) -> Option<&Table> { match self { - Value::Table(v) => Ok(v.clone()), - _ => { - Err(crate::Error::UnexpectedType("Table".to_string(), self.type_name().to_string())) - } + Value::Table(v) => Some(v), + _ => None, } } /// If `self` is an instance of Value::Userdata, returns a borrow to it. If it is not then /// an `UnexpectedType` error is returned. - pub fn as_userdata(&self) -> crate::Result> { + pub fn as_userdata(&self) -> Option<&AnyUserdata<'a>> { match self { - Value::Userdata(ud) => Ok(ud.clone()), - _ => { - Err(crate::Error::UnexpectedType("Userdata".to_string(), self.type_name().to_string())) - } + Value::Userdata(ud) => Some(ud), + _ => None } } /// If `self` is an instance of Value::String, the string is returned. If it is not then /// an `UnexpectedType` error is returned. - pub fn into_string(self) -> crate::Result { + pub fn into_string(self) -> Option { match self { - Value::String(s) => Ok(s), - _ => { - Err(crate::Error::UnexpectedType("String".to_string(), self.type_name().to_string())) - } + Value::String(s) => Some(s), + _ => None } } /// If `self` is an instance of Value::Function, the function is returned. If it is not then /// an `UnexpectedType` error is returned. - pub fn into_function(self) -> crate::Result> { + pub fn into_function(self) -> Option> { match self { - Value::Function(v) => Ok(v), - _ => { - Err(crate::Error::UnexpectedType("Function".to_string(), self.type_name().to_string())) - } + Value::Function(v) => Some(v), + _ => None, } } /// If `self` is an instance of Value::Table, the table is returned. If it is not then /// an `UnexpectedType` error is returned. - pub fn into_table(self) -> crate::Result> { + pub fn into_table(self) -> Option> { match self { - Value::Table(v) => Ok(v), - _ => { - Err(crate::Error::UnexpectedType("Table".to_string(), self.type_name().to_string())) - } + Value::Table(v) => Some(v), + _ => None, } } /// If `self` is an instance of Value::Userdata, the userdata is returned. If it is not then /// an `UnexpectedType` error is returned. - pub fn into_userdata(self) -> crate::Result> { + pub fn into_userdata(self) -> Option> { match self { - Value::Userdata(ud) => Ok(ud), - _ => { - Err(crate::Error::UnexpectedType("Userdata".to_string(), self.type_name().to_string())) - } + Value::Userdata(ud) => Some(ud), + _ => None, } } /// 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> { + pub fn into_value_vec(self) -> Option> { match self { - Value::Variable(v) => Ok(v), - _ => { - Err(crate::Error::UnexpectedType("ValueVec".to_string(), self.type_name().to_string())) - } + Value::Multi(v) => Some(v), + _ => None, } } } @@ -155,6 +143,10 @@ impl<'a> PushToLuaStack<'a> for Value<'a> { state.ensure_stack(1)?; lua::lua_pushnil(s); } + Value::Boolean(b) => { + state.ensure_stack(1)?; + lua::lua_pushboolean(s, *b as i32); + } Value::Number(n) => { state.ensure_stack(1)?; lua::lua_pushnumber(s, *n); @@ -167,9 +159,10 @@ impl<'a> PushToLuaStack<'a> for Value<'a> { lua::lua_pushstring(state.state_ptr(), cstr); } Value::Function(f) => f.push_to_lua_stack(state)?, + Value::Thread(t) => t.push_to_lua_stack(state)?, Value::Table(t) => t.push_to_lua_stack(state)?, Value::Userdata(ud) => ud.push_to_lua_stack(state)?, - Value::Variable(v) => { + Value::Multi(v) => { for v in v.iter() { v.push_to_lua_stack(state)?; } @@ -195,6 +188,12 @@ impl<'a> FromLuaStack<'a> for Value<'a> { Ok(Value::Nil) }, + lua::LUA_TBOOLEAN => { + let b = lua::lua_toboolean(s, -1) != 0; + lua::lua_pop(s, 1); + + Ok(Value::Boolean(b)) + }, lua::LUA_TNUMBER => { let n = lua::lua_tonumber(s, -1); lua::lua_pop(s, 1); @@ -214,6 +213,10 @@ impl<'a> FromLuaStack<'a> for Value<'a> { Function::from_lua_stack(state) .map(|f| Value::Function(f)) }, + lua::LUA_TTHREAD => { + LuaThread::from_lua_stack(state) + .map(|v| Value::Thread(v)) + }, lua::LUA_TTABLE => { Table::from_lua_stack(state) .map(|t| Value::Table(t)) @@ -226,7 +229,7 @@ impl<'a> FromLuaStack<'a> for Value<'a> { let s = lua::lua_typename(s, ty); let s = CStr::from_ptr(s); let s = s.to_str().unwrap(); - unimplemented!("Not yet able to get '{}' as a value from the stack", s); + unimplemented!("Not yet able to get '{}' ({}) as a value from the stack", s, ty); } }; @@ -235,7 +238,7 @@ impl<'a> FromLuaStack<'a> for Value<'a> { } pub trait AsLua<'a> { - fn as_lua(&self, lua: &'a State) -> crate::Result>; + fn as_lua(self, lua: &'a State) -> crate::Result>; } pub trait FromLua<'a>: Sized { @@ -251,35 +254,43 @@ pub trait FromLua<'a>: Sized { } impl<'a> AsLua<'a> for () { - fn as_lua(&self, _lua: &'a State) -> crate::Result> { + fn as_lua(self, _lua: &'a State) -> crate::Result> { Ok(Value::None) } } impl<'a> AsLua<'a> for Value<'a> { - fn as_lua(&self, _lua: &'a State) -> crate::Result> { - Ok(self.clone()) + fn as_lua(self, _lua: &'a State) -> crate::Result> { + Ok(self) } } impl<'a> AsLua<'a> for String { - fn as_lua(&self, _lua: &'a State) -> crate::Result> { - Ok(Value::String(self.clone())) + fn as_lua(self, _lua: &'a State) -> crate::Result> { + Ok(Value::String(self)) } } impl<'a> AsLua<'a> for &'a str { - fn as_lua(&self, _lua: &'a State) -> crate::Result> { + fn as_lua(self, _lua: &'a State) -> crate::Result> { Ok(Value::String(self.to_string())) } } impl<'a> FromLua<'a> for Value<'a> { - fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result { + fn from_lua(_: &'a State, val: Value<'a>) -> crate::Result { Ok(val) } } +impl<'a> FromLua<'a> for ValueVec<'a> { + fn from_lua(_: &'a State, val: Value<'a>) -> crate::Result { + let tyname = val.type_name(); + val.into_value_vec() + .ok_or(Error::type_mismatch("ValueVec", &tyname)) + } +} + impl<'a> FromLua<'a> for () { fn from_lua(_lua: &'a State, _val: Value<'a>) -> crate::Result { Ok(()) @@ -313,6 +324,13 @@ impl<'a> From>> for ValueVec<'a> { } } +impl<'a> From>> for ValueVec<'a> { + fn from(value: Vec>) -> Self { + Self(VecDeque::from(value)) + } +} + + impl<'a> FromLuaStack<'a> for ValueVec<'a> { unsafe fn from_lua_stack(state: &'a State) -> crate::Result { let s = state.state_ptr(); @@ -347,6 +365,21 @@ impl<'a> ValueVec<'a> { pub fn into_iter(self) -> std::collections::vec_deque::IntoIter> { self.0.into_iter() } + + /// Gets a ValueVec from the stack with a limit + pub fn from_stack_limit(state: &'a State, limit: usize) -> crate::Result> { + unsafe { + let s = state.state_ptr(); + + let mut vec = VecDeque::new(); + for _ in 1..(limit + 1) { + let v = Value::from_lua_stack(state)?; + vec.push_front(v); + } + + Ok(ValueVec(vec)) + } + } } impl<'a> From> for ValueVec<'a> { @@ -359,6 +392,10 @@ impl<'a> From> for ValueVec<'a> { /// A trait for getting something from a ValueVec from Lua pub trait FromLuaVec<'a>: Sized { + fn value_num() -> Option { + Some(1) + } + fn from_lua_value_vec(state: &'a State, values: ValueVec<'a>) -> crate::Result; } @@ -366,12 +403,16 @@ pub trait IntoLuaVec<'a>: Sized { fn into_lua_value_vec(self, state: &'a State) -> crate::Result>; } -/* impl<'a> FromLuaVec<'a> for ValueVec<'a> { +impl<'a> FromLuaVec<'a> for ValueVec<'a> { fn from_lua_value_vec(_state: &'a State, values: ValueVec<'a>) -> crate::Result { Ok(values) } + + fn value_num() -> Option { + None + } } - */ + impl<'a> IntoLuaVec<'a> for ValueVec<'a> { fn into_lua_value_vec(self, _state: &'a State) -> crate::Result> { Ok(self) @@ -389,11 +430,11 @@ impl<'a> IntoLuaVec<'a> for ValueVec<'a> { } } */ -impl<'a> FromLuaVec<'a> for ValueVec<'a> { +/* impl<'a> FromLuaVec<'a> for ValueVec<'a> { fn from_lua_value_vec(_state: &'a State, values: ValueVec<'a>) -> crate::Result { Ok(values) } -} +} */ impl<'a> PushToLuaStack<'a> for ValueVec<'a> { unsafe fn push_to_lua_stack(&self, state: &'a State) -> crate::Result<()> { @@ -421,7 +462,18 @@ macro_rules! impl_from_lua_vec_for_from_lua { }) } } + + fn value_num() -> Option { + Some(1) + } } + + + /* impl<'a> IntoLuaVec<'a> for $type<'a> { + fn into_lua_value_vec(self, state: &'a State) -> crate::Result> { + Ok(ValueVec::from(self.as_lua(state)?)) + } + } */ }; ($type: tt) => { impl<'a> FromLuaVec<'a> for $type { @@ -435,7 +487,17 @@ macro_rules! impl_from_lua_vec_for_from_lua { }) } } + + fn value_num() -> Option { + Some(1) + } } + + /* impl<'a> IntoLuaVec<'a> for $type { + fn into_lua_value_vec(self, state: &'a State) -> crate::Result> { + Ok(ValueVec::from(self.as_lua(state)?)) + } + } */ }; } @@ -456,6 +518,28 @@ 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: FromLua<'a>> FromLuaVec<'a> for T { + fn from_lua_value_vec(state: &'a State, mut values: ValueVec<'a>) -> crate::Result { + if let Some(v) = values.pop_front() { + Ok(T::from_lua(state, v)?) + } else { + Err(Error::Nil) + } + } +} */ + +impl<'a, T: AsLua<'a>> IntoLuaVec<'a> for T { + fn into_lua_value_vec(self, state: &'a State) -> crate::Result> { + let mut v = ValueVec::new(); + + let sval = self.as_lua(state)?; + if !sval.is_none() { + v.push_back(sval); + } + + Ok(v) + } +} 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 { @@ -468,6 +552,10 @@ impl<'a, T: Userdata + 'static> FromLuaVec<'a> for RefMut<'a, T> { }) } } + + fn value_num() -> Option { + Some(1) + } } impl<'a, T: Userdata + 'static> FromLuaVec<'a> for Ref<'a, T> { @@ -481,6 +569,10 @@ impl<'a, T: Userdata + 'static> FromLuaVec<'a> for Ref<'a, T> { }) } } + + fn value_num() -> Option { + Some(1) + } } impl<'a, T: TableProxy> FromLuaVec<'a> for Proxy { @@ -494,6 +586,10 @@ impl<'a, T: TableProxy> FromLuaVec<'a> for Proxy { }) } } + + fn value_num() -> Option { + Some(1) + } } impl<'a> FromLuaVec<'a> for () { @@ -507,18 +603,22 @@ impl<'a> FromLuaVec<'a> for () { }) } } -} -impl<'a> IntoLuaVec<'a> for () { - fn into_lua_value_vec(self, _state: &'a State) -> crate::Result> { - Ok(ValueVec::new()) + fn value_num() -> Option { + Some(0) } } +/* impl<'a> IntoLuaVec<'a> for () { + fn into_lua_value_vec(self, _state: &'a State) -> crate::Result> { + Ok(ValueVec::new()) + } +} */ + macro_rules! impl_from_lua_vec_tuple { - ( $count: expr, $first: tt, $( $name: tt ),+ ) => ( + ( $count: expr, $last: tt, $( $name: tt ),+ ) => ( #[allow(non_snake_case)] - impl<'a, $first: FromLua<'a>, $($name: FromLua<'a>,)+> FromLuaVec<'a> for ($first, $($name,)+) { + impl<'a, $($name: FromLua<'a>,)* $last: FromLuaVec<'a>> FromLuaVec<'a> for ($($name,)* $last,) { fn from_lua_value_vec(state: &'a State, mut values: ValueVec<'a>) -> crate::Result { if values.len() != $count { return Err(crate::Error::IncorrectArgCount { @@ -527,36 +627,42 @@ macro_rules! impl_from_lua_vec_tuple { }); } - let f = $first::from_lua(state, values.pop_front().unwrap()) - .map_err(|e| crate::Error::ValueVecError { value_idx: 0, error: std::sync::Arc::new(e) })?; - - let mut idx = 0; + + let mut idx = -1; // will be added to 0 on the first iter of the tuple let ($( $name, )+) = ( $( $name::from_lua(state, values.pop_front().unwrap()) .map_err(|e| crate::Error::ValueVecError { value_idx: {idx += 1; idx}, error: std::sync::Arc::new(e) })?, )+ ); - Ok( (f, $( $name, )+) ) + let f = $last::from_lua_value_vec(state, values) + .map_err(|e| crate::Error::ValueVecError { value_idx: {idx += 1; idx}, error: std::sync::Arc::new(e) })?; + + Ok( ( $( $name, )* f,) ) + } + + fn value_num() -> Option { + Some($count) } } #[allow(non_snake_case)] - impl<'a, $first: AsLua<'a>, $($name: AsLua<'a>,)+> IntoLuaVec<'a> for ($first, $($name,)+) { + impl<'a, $($name: AsLua<'a>,)* $last: IntoLuaVec<'a>,> IntoLuaVec<'a> for ($($name,)+ $last,) { fn into_lua_value_vec(self, state: &'a State) -> crate::Result> { - let ($first, $($name,)+) = self; + let ($($name,)+ $last,) = self; let mut vals = ValueVec::new(); - let v = $first.as_lua(state) - .map_err(|e| crate::Error::ValueVecError { value_idx: 0, error: std::sync::Arc::new(e) })?; - vals.push_back(v); - - let mut idx = 0; + + let mut idx = -1; $( let v = $name.as_lua(state) .map_err(|e| crate::Error::ValueVecError { value_idx: {idx += 1; idx}, error: std::sync::Arc::new(e) })?; vals.push_back(v); )+ + let mut v = $last.into_lua_value_vec(state) + .map_err(|e| crate::Error::ValueVecError { value_idx: {idx += 1; idx}, error: std::sync::Arc::new(e) })?; + vals.append(&mut v); + Ok(vals) } } @@ -579,6 +685,10 @@ macro_rules! impl_from_lua_vec_tuple { .map_err(|e| crate::Error::ValueVecError { value_idx: 0, error: std::sync::Arc::new(e) })?; Ok( (o,) ) } + + fn value_num() -> Option { + Some(1) + } } #[allow(non_snake_case)] diff --git a/src/variadic.rs b/src/variadic.rs index 1b76f82..aaca8d6 100644 --- a/src/variadic.rs +++ b/src/variadic.rs @@ -27,20 +27,42 @@ impl<'a, T: FromLua<'a> + AsLua<'a>> DerefMut for Variadic<'a, T> { 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()?; + let tyname = val.type_name(); + let vals = val.into_value_vec() + .ok_or(Error::Runtime(format!("failure to get Variadic<_> with ValueVec from {}", tyname)))?; + //.ok_or(Error::type_mismatch("Variadic<>", &tyname))?; 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); + .map_err(|e| match e { + Error::TypeMismatch { expected: ty, got, } => { + let ty = format!("Variadic<{}> from ValueVec", ty); + Error::TypeMismatch { expected: ty, got } + }, + _ => e, + })? + ); + } - Error::UnexpectedType(ty, ret) - }, - _ => e, - })? + Ok(Self(vec, PhantomData)) + } +} + +impl<'a, T: FromLua<'a> + AsLua<'a>> FromLuaVec<'a> for Variadic<'a, T> { + fn from_lua_value_vec(state: &'a crate::State, values: ValueVec<'a>) -> crate::Result { + let mut vec = VecDeque::new(); + + for val in values.into_iter() { + vec.push_back( + T::from_lua(state, val) + .map_err(|e| match e { + Error::TypeMismatch { expected: ty, got, } => { + let ty = format!("Variadic<{}> from ValueVec", ty); + Error::TypeMismatch { expected: ty, got } + }, + _ => e, + })? ); } @@ -49,15 +71,18 @@ impl<'a, T: FromLua<'a> + AsLua<'a>> FromLua<'a> for Variadic<'a, T> { } 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?)) + fn as_lua(self, lua: &'a crate::State) -> crate::Result> { + let v: Result, _> = self.0.into_iter() + .map(|v| v.as_lua(lua)) + .collect(); + + Value::Multi(ValueVec::from(v?)) .as_lua(lua) } } -impl<'a, T: FromLua<'a> + AsLua<'a>> FromLuaVec<'a> for Variadic<'a, T> { +/* 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)) + Variadic::from_lua(state, Value::Multi(values)) } -} \ No newline at end of file +} */ \ No newline at end of file