Create a chunk struct, replace the traits created for Function with FromLua, ToLua, FromLuaVec, etc.
This commit is contained in:
parent
2848d1deee
commit
f3c0dc1930
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
197
src/function.rs
197
src/function.rs
|
@ -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);
|
||||||
|
|
||||||
self.push_to_lua_stack(self.state)?;
|
|
||||||
args.push_args_to_lua_stack(self.state)?;
|
|
||||||
|
|
||||||
let arg_len = args.len() as i32;
|
|
||||||
let res_len = R::len() as i32;
|
|
||||||
let s = self.state.state_ptr();
|
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 args_val = args.as_lua(self.state)?;
|
||||||
let s = CStr::from_ptr(s);
|
let args_len = match args_val {
|
||||||
let s = s.to_str().unwrap();
|
Value::Variable(v) => v.len(),
|
||||||
|
Value::None => 0,
|
||||||
|
_ => 1,
|
||||||
|
} as _;
|
||||||
|
|
||||||
return Err(crate::Error::runtime(s));
|
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)?;
|
||||||
|
|
||||||
|
let args_val = args.as_lua(self.state)?;
|
||||||
|
args_val.push_to_lua_stack(self.state)?;
|
||||||
|
|
||||||
|
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);
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::results_from_lua_stack(self.state)
|
R::from_lua(self.state, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,129 +100,4 @@ impl<'a> AsLua<'a> for Function<'a> {
|
||||||
fn as_lua(&self, _lua: &'a State) -> crate::Result<crate::Value<'a>> {
|
fn as_lua(&self, _lua: &'a State) -> crate::Result<crate::Value<'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 }
|
|
26
src/main.rs
26
src/main.rs
|
@ -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(())
|
||||||
|
|
82
src/state.rs
82
src/state.rs
|
@ -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);
|
||||||
|
|
114
src/value.rs
114
src/value.rs
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue