Create a chunk struct, replace the traits created for Function with FromLua, ToLua, FromLuaVec, etc.

This commit is contained in:
SeanOMik 2024-01-28 20:02:12 -05:00
parent 2848d1deee
commit f3c0dc1930
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
5 changed files with 297 additions and 199 deletions

77
src/chunk.rs Executable file
View File

@ -0,0 +1,77 @@
use std::borrow::{Borrow, Cow};
use crate::{AsLua, FromLua, Function, State};
pub struct Chunk<'a> {
state: &'a State,
name: String,
data: Cow<'a, [u8]>,
func: Function<'a>,
}
impl<'a> Chunk<'a> {
pub(crate) fn new(state: &'a State, name: String, data: Cow<'a, [u8]>, func: Function<'a>) -> Self {
Self {
state,
name,
data,
func,
}
}
/// Construct a Lua Chunk from bytes
/* pub fn from_bytes(name: &'a str, bytes: &'a [u8]) -> Self {
Self {
name,
data: bytes
}
}
/// Construct a Lua Chunk from a string
pub fn from_str(name: &'a str, text: &'a str) -> Self {
Self {
name,
data: text.as_bytes(),
}
} */
/// Execute the chunk in the Lua context
pub fn execute<A, R>(&'a self, args: A) -> crate::Result<R>
where
A: AsLua<'a>,
R: FromLua<'a>
{
self.state.execute_chunk::<A, R>(self, args)
}
/// Returns the name of the Chunk
pub fn name(&self) -> &str {
&self.name
}
/// Returns the data of the chunk
pub fn data(&self) -> &[u8] {
self.data.borrow()
}
/// Returns a handle to the chunk's executable function
pub fn function(&self) -> Function {
self.func.clone()
}
}
pub trait IntoChunkData<'a> {
fn into_chunk(self) -> Cow<'a, [u8]>;
}
impl<'a> IntoChunkData<'a> for &'a str {
fn into_chunk(self) -> Cow<'a, [u8]> {
Cow::Borrowed(self.as_bytes())
}
}
impl<'a> IntoChunkData<'a> for &'a [u8] {
fn into_chunk(self) -> Cow<'a, [u8]> {
Cow::Borrowed(self)
}
}

View File

@ -1,13 +1,14 @@
use std::ffi::CStr; use std::sync::Arc;
use crate::{AsLua, FromLuaStack, LuaRef, PushToLuaStack, StackGuard, State}; use crate::{AsLua, FromLua, FromLuaStack, LuaRef, PushToLuaStack, StackGuard, State, Value, ValueVec};
use mlua_sys as lua; use mlua_sys as lua;
#[derive(Clone)] #[derive(Clone)]
pub struct Function<'a> { pub struct Function<'a> {
state: &'a State, state: &'a State,
lref: LuaRef lref: LuaRef,
pub(crate) error_handler: Option<Arc<Function<'a>>>,
} }
impl<'a> FromLuaStack<'a> for Function<'a> { impl<'a> FromLuaStack<'a> for Function<'a> {
@ -15,6 +16,7 @@ impl<'a> FromLuaStack<'a> for Function<'a> {
Ok(Self { Ok(Self {
state, state,
lref: LuaRef::from_stack(state)?, lref: LuaRef::from_stack(state)?,
error_handler: None,
}) })
} }
} }
@ -30,32 +32,66 @@ impl<'a> Function<'a> {
Self { Self {
state, state,
lref, lref,
error_handler: None,
} }
} }
pub fn exec<A, R>(&self, args: A) -> crate::Result<R> pub fn exec<A, R>(&self, args: A) -> crate::Result<R>
where where
A: PushToLuaStackMulti<'a>, A: AsLua<'a>,
R: FromLuaStackMulti<'a>, R: FromLua<'a>,
{ {
unsafe { unsafe {
let _g = StackGuard::new(self.state); let _g = StackGuard::new(self.state);
let s = self.state.state_ptr();
let args_val = args.as_lua(self.state)?;
let args_len = match args_val {
Value::Variable(v) => v.len(),
Value::None => 0,
_ => 1,
} as _;
self.state.ensure_stack(2 + args_len)?;
let handler_idx = match &self.error_handler {
Some(handler) => {
handler.push_to_lua_stack(self.state)?;
lua::lua_gettop(s)
},
None => 0,
};
self.push_to_lua_stack(self.state)?; self.push_to_lua_stack(self.state)?;
args.push_args_to_lua_stack(self.state)?;
let arg_len = args.len() as i32; let args_val = args.as_lua(self.state)?;
let res_len = R::len() as i32; args_val.push_to_lua_stack(self.state)?;
let s = self.state.state_ptr();
if lua::lua_pcall(s, arg_len, res_len, 0) != 0 {
let s = lua::lua_tostring(s, -1);
let s = CStr::from_ptr(s);
let s = s.to_str().unwrap();
return Err(crate::Error::runtime(s)); match lua::lua_pcall(s, args_len, lua::LUA_MULTRET, handler_idx) {
lua::LUA_ERRRUN => {
let er = self.state.get_error_str();
return Err(crate::Error::runtime(er));
},
lua::LUA_ERRMEM => {
return Err(crate::Error::MemoryAlloc);
},
lua::LUA_ERRERR => {
let er = self.state.get_error_str();
// if this panics, its a bug
panic!("Failure when trying to execute error handler function! ({})", er);
},
_ => {}
} }
R::results_from_lua_stack(self.state) let ret_count = lua::lua_gettop(s);
let val = if ret_count > 1 {
let vals = ValueVec::from_lua_stack(self.state)?;
Value::Variable(vals)
} else {
Value::from_lua_stack(self.state)?
};
R::from_lua(self.state, val)
} }
} }
} }
@ -65,128 +101,3 @@ impl<'a> AsLua<'a> for Function<'a> {
Ok(crate::Value::Function(self.clone())) Ok(crate::Value::Function(self.clone()))
} }
} }
pub trait PushToLuaStackMulti<'a> {
fn len(&self) -> usize;
fn push_args_to_lua_stack(&self, state: &'a State) -> crate::Result<()>;
}
impl<'a, T> PushToLuaStackMulti<'a> for T
where
T: PushToLuaStack<'a>,
{
fn len(&self) -> usize {
1
}
fn push_args_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
unsafe {
self.push_to_lua_stack(state)?;
}
Ok(())
}
}
pub trait FromLuaStackMulti<'a>: Sized {
fn len() -> usize;
fn results_from_lua_stack(state: &'a State) -> crate::Result<Self>;
}
impl<'a> FromLuaStackMulti<'a> for () {
fn len() -> usize {
1
}
fn results_from_lua_stack(_state: &'a State) -> crate::Result<Self> {
Ok(())
}
}
impl<'a, T: FromLuaStack<'a>> FromLuaStackMulti<'a> for T {
fn len() -> usize {
1
}
fn results_from_lua_stack(state: &'a State) -> crate::Result<Self> {
unsafe { T::from_lua_stack(state) }
}
}
macro_rules! impl_function_arg_tuple {
( $count: expr, $first: tt, $( $name: tt ),+ ) => (
#[allow(non_snake_case)]
impl<'a, $first: PushToLuaStack<'a>, $($name: PushToLuaStack<'a>,)+> PushToLuaStackMulti<'a> for ($first, $($name,)+) {
fn len(&self) -> usize {
// this will end up generating $count - 1 - 1 - 1... hopefully the compiler will
// optimize that out
$count
}
fn push_args_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
let ($first, $($name,)+) = self;
unsafe {
$first.push_to_lua_stack(state)?;
$( $name.push_to_lua_stack(state)?; )+
}
Ok(())
}
}
#[allow(non_snake_case)]
impl<'a, $first: FromLuaStack<'a>, $($name: FromLuaStack<'a>,)+> FromLuaStackMulti<'a> for ($first, $($name,)+) {
fn len() -> usize {
$count
}
fn results_from_lua_stack(state: &'a State) -> crate::Result<Self> {
unsafe {
let ($( $name, )+ $first) = ( $( $name::from_lua_stack(state)?, )+ $first::from_lua_stack(state)? );
Ok( ($first, $( $name, )+) )
}
//Ok(unsafe { ( $( $name::from_lua_stack(state)?, )+ $first::from_lua_stack(state)? ) })
//Ok(unsafe { ( $first::from_lua_stack(state)?, $( $name::from_lua_stack(state)?, )+ ) })
}
}
impl_function_arg_tuple!( $count - 1, $( $name ),+ );
);
// implements PushToLuaStackMulti and FromLuaStackMulti for a tuple with a single element
( $count: expr, $only: tt ) => {
#[allow(non_snake_case)]
impl<'a, $only: PushToLuaStack<'a>> PushToLuaStackMulti<'a> for ($only,) {
fn len(&self) -> usize {
1
}
fn push_args_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
let (a,) = self;
unsafe {
a.push_to_lua_stack(state)?;
}
Ok(())
}
}
impl<'a, $only: FromLuaStack<'a>> FromLuaStackMulti<'a> for ($only,) {
fn len() -> usize {
1
}
fn results_from_lua_stack(state: &'a State) -> crate::Result<Self> {
Ok(unsafe { ( $only::from_lua_stack(state)?, ) })
}
}
};
}
// hopefully 16 is more than enough
// if you have 16 function results, and need more than 16, you NEED help
impl_function_arg_tuple! { 16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16 }

View File

@ -23,6 +23,9 @@ use userdata::*;
pub mod util; pub mod util;
use util::*; use util::*;
pub mod chunk;
use chunk::*;
fn main() -> Result<()> { fn main() -> Result<()> {
let lua = State::new(); let lua = State::new();
lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]); lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]);
@ -37,8 +40,7 @@ fn main() -> Result<()> {
let f = lua.create_function(a)?; let f = lua.create_function(a)?;
globals.set("native_test", f)?; globals.set("native_test", f)?;
//let ud = lua.create_userdata("Vec2", Vec2 { x: 0.0, y: 0.0})?; let ud = lua.create_userdata(UserdataProxy::<Vec2>::new())?;
let ud = lua.create_userdata("Vec2", UserdataProxy::<Vec2>::new())?;
globals.set("Vec2", ud)?; globals.set("Vec2", ud)?;
let tbl = lua.create_table()?; let tbl = lua.create_table()?;
@ -47,7 +49,7 @@ fn main() -> Result<()> {
//let globals = lua.globals()?; //let globals = lua.globals()?;
globals.set("X", tbl)?; globals.set("X", tbl)?;
let res = lua.execute(r#" let chunk = lua.load("text.lua", r#"
require "util" require "util"
--[[function dump_table(tbl) --[[function dump_table(tbl)
@ -85,6 +87,7 @@ fn main() -> Result<()> {
cool_num = 50 cool_num = 50
print("Lua is about to exec native_test")
local res = native_test(50) local res = native_test(50)
print("Lua got " .. res .. " back from rust!") print("Lua got " .. res .. " back from rust!")
@ -119,7 +122,13 @@ fn main() -> Result<()> {
end end
f3(v1, v2) f3(v1, v2)
"#); "#)?;
// I don't care about the result of this execution, so I set the result as a
// Value which can be anything
//
// Chunks can also be executed with: `chunk.execute(())?;`
let res = lua.execute_chunk::<_, Value>(&chunk, ());
// if unwrapped, the new lines in the message would be escaped making // if unwrapped, the new lines in the message would be escaped making
// the traceback in the error difficult to read. // the traceback in the error difficult to read.
@ -347,6 +356,7 @@ impl<'a> PushToLuaStack<'a> for &str {
} }
} }
#[allow(dead_code)]
pub struct Vec3 { pub struct Vec3 {
x: f32, x: f32,
y: f32, y: f32,
@ -354,7 +364,7 @@ pub struct Vec3 {
} }
impl Userdata for Vec3 { impl Userdata for Vec3 {
fn build<'a>(builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()> { fn build<'a>(_builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()> {
todo!() todo!()
} }
@ -379,7 +389,7 @@ impl Userdata for Vec2 {
.field_setter("y", |_, this, y: f32| this.y = y) .field_setter("y", |_, this, y: f32| this.y = y)
.function("new", |lua, (x, y)| { .function("new", |lua, (x, y)| {
lua.create_userdata("Vec2", Vec2 { x, y, }) lua.create_userdata(Vec2 { x, y, })
}) })
// method test // method test
@ -390,7 +400,7 @@ impl Userdata for Vec2 {
let rx = rhs.x; let rx = rhs.x;
let ry = rhs.y; let ry = rhs.y;
lua.create_userdata("Vec2", Vec2 { x: lx + rx, y: ly + ry, }) lua.create_userdata(Vec2 { x: lx + rx, y: ly + ry, })
}) })
.meta_method(MetaMethod::Add, |lua, lhs: &Vec2, (rhs,): (&Vec2,)| { .meta_method(MetaMethod::Add, |lua, lhs: &Vec2, (rhs,): (&Vec2,)| {
@ -400,7 +410,7 @@ impl Userdata for Vec2 {
let rx = rhs.x; let rx = rhs.x;
let ry = rhs.y; let ry = rhs.y;
lua.create_userdata("Vec2", Vec2 { x: lx + rx, y: ly + ry, }) lua.create_userdata(Vec2 { x: lx + rx, y: ly + ry, })
}); });
Ok(()) Ok(())

View File

@ -1,9 +1,9 @@
use core::ffi; use core::ffi;
use std::{alloc::{self, Layout}, any::TypeId, collections::{HashMap, VecDeque}, ffi::{CStr, CString}, mem, ptr::{self, NonNull}, str::Utf8Error}; use std::{alloc::{self, Layout}, any::TypeId, collections::HashMap, ffi::{CStr, CString}, mem, ptr::{self, NonNull}, str::Utf8Error, sync::Arc};
use mlua_sys as lua; use mlua_sys as lua;
use crate::{lua_error_guard, AnyUserdata, AsLua, Error, FromLuaStack, FromLuaVec, Function, LuaRef, MetaMethod, PushToLuaStack, PushToLuaStackMulti, Result, StackGuard, Table, Userdata, UserdataBuilder, Value, ValueVec}; use crate::{lua_error_guard, AnyUserdata, IntoChunkData, AsLua, Chunk, Error, FromLua, FromLuaStack, FromLuaVec, Function, LuaRef, MetaMethod, PushToLuaStack, Result, StackGuard, Table, Userdata, UserdataBuilder, Value, ValueVec};
pub fn ptr_to_string(ptr: *const i8) -> std::result::Result<String, Utf8Error> { pub fn ptr_to_string(ptr: *const i8) -> std::result::Result<String, Utf8Error> {
let c = unsafe { CStr::from_ptr(ptr) }; let c = unsafe { CStr::from_ptr(ptr) };
@ -150,7 +150,8 @@ impl State {
} }
} }
unsafe fn get_error_str(&self) -> &str { /// Returns the string of an error on the top of the stack
pub(crate) unsafe fn get_error_str(&self) -> &str {
let error_c = CStr::from_ptr(lua::lua_tostring(self.state_ptr(), -1)); let error_c = CStr::from_ptr(lua::lua_tostring(self.state_ptr(), -1));
let error_str = error_c.to_str() let error_str = error_c.to_str()
.unwrap_or_else(|_| { .unwrap_or_else(|_| {
@ -167,18 +168,24 @@ impl State {
self.traceback(Some(&msg)) self.traceback(Some(&msg))
} }
pub fn execute(&self, text: &str) -> Result<()> { pub fn load<'a, C>(&'a self, name: &str, chunk: C) -> Result<Chunk>
let text = format!("{}\0", text); where
C: IntoChunkData<'a> + 'a
{
unsafe { unsafe {
self.ensure_stack(3)?; self.ensure_stack(1)?;
let _g = StackGuard::new(self); let _g = StackGuard::new(self);
let s = self.lua.as_ptr();
let lua = self.lua.as_ptr(); let chunk_data = chunk.into_chunk();
let text_c = text.as_ptr().cast(); let chunk_ptr = chunk_data.as_ptr().cast();
// zero terminated name
let name_zero = format!("{}\0", name);
let name_zero = name_zero.as_ptr().cast();
// Subtract one from the length to exclude the null terminator // Subtract one from the length to exclude the null terminator
match lua::luaL_loadbuffer(self.state_ptr(), text_c, text.len() - 1, "test.lua\0".as_ptr().cast()) { match lua::luaL_loadbuffer(s, chunk_ptr, chunk_data.len() - 1, name_zero) {
lua::LUA_ERRSYNTAX => { lua::LUA_ERRSYNTAX => {
return Err(Error::Syntax(self.get_error_str().to_string())); return Err(Error::Syntax(self.get_error_str().to_string()));
}, },
@ -188,30 +195,25 @@ impl State {
_ => {}, _ => {},
} }
let handler = self.create_function(|lua, msg: String| { let func = Function::from_lua_stack(self)?;
lua.state_error_handler(msg)
})?;
handler.push_to_lua_stack(self)?;
lua::lua_insert(lua, -2);
match lua::lua_pcall(lua, 0, lua::LUA_MULTRET, -2) { Ok(Chunk::new(self, name.to_string(), chunk_data, func))
lua::LUA_ERRRUN => {
let er = self.get_error_str();
return Err(Error::runtime(er));
},
lua::LUA_ERRMEM => {
return Err(Error::MemoryAlloc);
},
lua::LUA_ERRERR => {
let er = self.get_error_str();
// if this panics, its a bug
panic!("Failure when trying to execute error handler function! ({})", er);
},
_ => {}
}
} }
}
Ok(()) pub fn execute_chunk<'a, A, R>(&'a self, chunk: &'a Chunk, args: A) -> Result<R>
where
A: AsLua<'a>,
R: FromLua<'a>
{
let handler = self.create_function(|lua, msg: String| {
lua.state_error_handler(msg)
})?;
let mut chunk_func = chunk.function();
chunk_func.error_handler = Some(Arc::new(handler));
chunk_func.exec::<A, R>(args)
} }
pub fn expose_libraries<L: Into<StdLibraries>>(&self, libs: L) { pub fn expose_libraries<L: Into<StdLibraries>>(&self, libs: L) {
@ -283,7 +285,7 @@ impl State {
pub fn create_function<'a, A, R, F>(&self, f: F) -> Result<Function> pub fn create_function<'a, A, R, F>(&self, f: F) -> Result<Function>
where where
A: FromLuaVec<'a>, A: FromLuaVec<'a>,
R: PushToLuaStackMulti<'a>, R: AsLua<'a>, //PushToLuaStackMulti<'a>,
F: Fn(&'a State, A) -> Result<R> + 'static, F: Fn(&'a State, A) -> Result<R> + 'static,
{ {
unsafe extern "C-unwind" fn rust_closure(s: *mut lua::lua_State) -> i32 { unsafe extern "C-unwind" fn rust_closure(s: *mut lua::lua_State) -> i32 {
@ -332,11 +334,21 @@ impl State {
lua_error_guard(lua, || { lua_error_guard(lua, || {
let vec = ValueVec::from_lua_stack(lua)?; let vec = ValueVec::from_lua_stack(lua)?;
let args = A::from_lua_value_vec(lua, vec)?; let args = A::from_lua_value_vec(lua, vec)?;
let r = f(lua, args)?; let r = f(lua, args)?;
r.push_args_to_lua_stack(lua)?; let r_val = r.as_lua(lua)?;
Ok(r.len() as i32)
let args_len = match &r_val {
Value::Variable(v) => v.len(),
Value::None => 0,
_ => 1,
} as _;
r_val.push_to_lua_stack(lua)?;
Ok(args_len)
}) })
} }
}; };
@ -361,7 +373,7 @@ impl State {
} }
/// Create userdata /// Create userdata
pub fn create_userdata<T: Userdata + 'static>(&self, name: &str, data: T) -> Result<AnyUserdata> { pub fn create_userdata<T: Userdata + 'static>(&self, data: T) -> Result<AnyUserdata> {
unsafe { unsafe {
self.ensure_stack(2)?; self.ensure_stack(2)?;
let _g = StackGuard::new(self); let _g = StackGuard::new(self);

View File

@ -15,6 +15,7 @@ pub enum Value<'a> {
Function(Function<'a>), Function(Function<'a>),
Table(Table<'a>), Table(Table<'a>),
Userdata(AnyUserdata<'a>), Userdata(AnyUserdata<'a>),
Variable(ValueVec<'a>),
} }
impl<'a> Value<'a> { impl<'a> Value<'a> {
@ -31,6 +32,7 @@ impl<'a> Value<'a> {
Value::Function(_) => "Function".to_string(), Value::Function(_) => "Function".to_string(),
Value::Table(_) => "Table".to_string(), Value::Table(_) => "Table".to_string(),
Value::Userdata(ud) => ud.name().unwrap(), Value::Userdata(ud) => ud.name().unwrap(),
Value::Variable(_) => todo!(),
} }
} }
@ -79,9 +81,7 @@ impl<'a> PushToLuaStack<'a> for Value<'a> {
let s = state.state_ptr(); let s = state.state_ptr();
match self { match self {
Value::None => { Value::None => { },
},
Value::Nil => { Value::Nil => {
state.ensure_stack(1)?; state.ensure_stack(1)?;
lua::lua_pushnil(s); lua::lua_pushnil(s);
@ -100,6 +100,11 @@ impl<'a> PushToLuaStack<'a> for Value<'a> {
Value::Function(f) => f.push_to_lua_stack(state)?, Value::Function(f) => f.push_to_lua_stack(state)?,
Value::Table(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::Userdata(ud) => ud.push_to_lua_stack(state)?,
Value::Variable(v) => {
for v in v.iter() {
v.push_to_lua_stack(state)?;
}
}
} }
Ok(()) Ok(())
@ -108,10 +113,13 @@ impl<'a> PushToLuaStack<'a> for Value<'a> {
impl<'a> FromLuaStack<'a> for Value<'a> { impl<'a> FromLuaStack<'a> for Value<'a> {
unsafe fn from_lua_stack(state: &'a State) -> crate::Result<Self> { unsafe fn from_lua_stack(state: &'a State) -> crate::Result<Self> {
let s = state.state_ptr(); let s = state.state_ptr();
let ty = lua::lua_type(s, -1);
if lua::lua_gettop(s) == 0 {
return Ok(Self::None);
}
let ty = lua::lua_type(s, -1);
let val = match ty { let val = match ty {
lua::LUA_TNIL => { lua::LUA_TNIL => {
lua::lua_pop(s, 1); lua::lua_pop(s, 1);
@ -129,8 +137,9 @@ impl<'a> FromLuaStack<'a> for Value<'a> {
lua::lua_pop(s, 1); lua::lua_pop(s, 1);
let cstr = CStr::from_ptr(cstr); let cstr = CStr::from_ptr(cstr);
let lua_str = cstr.to_str().unwrap().to_string(); let lua_str = cstr.to_string_lossy();
Ok(Value::String(lua_str)) //let lua_str = cstr.to_str().unwrap().to_string();
Ok(Value::String(lua_str.to_string()))
}, },
lua::LUA_TFUNCTION => { lua::LUA_TFUNCTION => {
Function::from_lua_stack(state) Function::from_lua_stack(state)
@ -166,7 +175,25 @@ pub trait FromLua<'a>: Sized {
impl<'a> AsLua<'a> for () { impl<'a> AsLua<'a> for () {
fn as_lua(&self, _lua: &'a State) -> crate::Result<Value<'a>> { fn as_lua(&self, _lua: &'a State) -> crate::Result<Value<'a>> {
Ok(Value::Nil) Ok(Value::None)
}
}
impl<'a> AsLua<'a> for Value<'a> {
fn as_lua(&self, _lua: &'a State) -> crate::Result<Value<'a>> {
Ok(self.clone())
}
}
impl<'a> AsLua<'a> for String {
fn as_lua(&self, _lua: &'a State) -> crate::Result<Value<'a>> {
Ok(Value::String(self.clone()))
}
}
impl<'a> AsLua<'a> for &'a str {
fn as_lua(&self, _lua: &'a State) -> crate::Result<Value<'a>> {
Ok(Value::String(self.to_string()))
} }
} }
@ -176,7 +203,13 @@ impl<'a> FromLua<'a> for Value<'a> {
} }
} }
#[derive(Default)] impl<'a> FromLua<'a> for () {
fn from_lua(_lua: &'a State, _val: Value<'a>) -> crate::Result<Self> {
Ok(())
}
}
#[derive(Default, Clone)]
pub struct ValueVec<'a>(VecDeque<Value<'a>>); pub struct ValueVec<'a>(VecDeque<Value<'a>>);
impl<'a> Deref for ValueVec<'a> { impl<'a> Deref for ValueVec<'a> {
@ -238,11 +271,32 @@ pub trait FromLuaVec<'a>: Sized {
fn from_lua_value_vec(state: &'a State, values: ValueVec<'a>) -> crate::Result<Self>; fn from_lua_value_vec(state: &'a State, values: ValueVec<'a>) -> crate::Result<Self>;
} }
impl<'a> FromLuaVec<'a> for () { pub trait IntoLuaVec<'a>: Sized {
fn from_lua_value_vec(_state: &'a State, _values: ValueVec<'a>) -> crate::Result<Self> { fn into_lua_value_vec(self, state: &'a State) -> crate::Result<ValueVec<'a>>;
Ok(()) }
/* impl<'a> FromLuaVec<'a> for ValueVec<'a> {
fn from_lua_value_vec(_state: &'a State, values: ValueVec<'a>) -> crate::Result<Self> {
Ok(values)
} }
} }
*/
impl<'a> IntoLuaVec<'a> for ValueVec<'a> {
fn into_lua_value_vec(self, _state: &'a State) -> crate::Result<ValueVec<'a>> {
Ok(self)
}
}
/* impl<'a> FromLua<'a> for ValueVec<'a> {
fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result<Self> {
match val {
Value::Variable(v) => Ok(v),
_ => {
Ok(ValueVec::from(val))
}
}
}
} */
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<Self> { fn from_lua_value_vec(_state: &'a State, values: ValueVec<'a>) -> crate::Result<Self> {
@ -267,7 +321,6 @@ macro_rules! impl_from_lua_vec_tuple {
( $count: expr, $first: tt, $( $name: tt ),+ ) => ( ( $count: expr, $first: tt, $( $name: tt ),+ ) => (
#[allow(non_snake_case)] #[allow(non_snake_case)]
impl<'a, $first: FromLua<'a>, $($name: FromLua<'a>,)+> FromLuaVec<'a> for ($first, $($name,)+) { impl<'a, $first: FromLua<'a>, $($name: FromLua<'a>,)+> FromLuaVec<'a> for ($first, $($name,)+) {
fn from_lua_value_vec(state: &'a State, mut values: ValueVec<'a>) -> crate::Result<Self> { fn from_lua_value_vec(state: &'a State, mut values: ValueVec<'a>) -> crate::Result<Self> {
if values.len() != $count { if values.len() != $count {
return Err(crate::Error::IncorrectArgCount { return Err(crate::Error::IncorrectArgCount {
@ -289,6 +342,27 @@ macro_rules! impl_from_lua_vec_tuple {
} }
} }
#[allow(non_snake_case)]
impl<'a, $first: AsLua<'a>, $($name: AsLua<'a>,)+> IntoLuaVec<'a> for ($first, $($name,)+) {
fn into_lua_value_vec(self, state: &'a State) -> crate::Result<ValueVec<'a>> {
let ($first, $($name,)+) = 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 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);
)+
Ok(vals)
}
}
impl_from_lua_vec_tuple!( $count - 1, $( $name ),+ ); impl_from_lua_vec_tuple!( $count - 1, $( $name ),+ );
); );
@ -308,6 +382,20 @@ macro_rules! impl_from_lua_vec_tuple {
Ok( (o,) ) Ok( (o,) )
} }
} }
#[allow(non_snake_case)]
impl<'a, $only: AsLua<'a>> IntoLuaVec<'a> for ($only,) {
fn into_lua_value_vec(self, state: &'a State) -> crate::Result<ValueVec<'a>> {
let ($only,) = self;
let mut vals = ValueVec::new();
let v = $only.as_lua(state)
.map_err(|e| crate::Error::ValueVecError { value_idx: 0, error: std::sync::Arc::new(e) })?;
vals.push_back(v);
Ok(vals)
}
}
}; };
} }