2017-05-21 19:50:59 -04:00
|
|
|
use std::fmt;
|
|
|
|
use std::ops::{Deref, DerefMut};
|
|
|
|
use std::iter::FromIterator;
|
|
|
|
use std::cell::{RefCell, Ref, RefMut};
|
|
|
|
use std::ptr;
|
|
|
|
use std::ffi::{CStr, CString};
|
|
|
|
use std::any::TypeId;
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
use std::collections::{HashMap, VecDeque};
|
|
|
|
use std::collections::hash_map::Entry as HashMapEntry;
|
|
|
|
use std::os::raw::{c_char, c_int, c_void};
|
|
|
|
|
|
|
|
use ffi;
|
|
|
|
use error::*;
|
|
|
|
use util::*;
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// A dynamically typed Lua value.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub enum LuaValue<'lua> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The Lua value `nil`.
|
2017-05-21 19:50:59 -04:00
|
|
|
Nil,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The Lua value `true` or `false`.
|
2017-05-21 19:50:59 -04:00
|
|
|
Boolean(bool),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// A "light userdata" object, equivalent to a raw pointer.
|
2017-07-19 20:15:46 -04:00
|
|
|
LightUserData(LuaLightUserData),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// An integer number.
|
|
|
|
///
|
|
|
|
/// Any Lua number convertible to a `LuaInteger` will be represented as this variant.
|
2017-05-21 19:50:59 -04:00
|
|
|
Integer(LuaInteger),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// A floating point number.
|
2017-05-21 19:50:59 -04:00
|
|
|
Number(LuaNumber),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// An interned string, managed by Lua.
|
|
|
|
///
|
|
|
|
/// Unlike Rust strings, Lua strings may not be valid UTF-8.
|
2017-05-21 19:50:59 -04:00
|
|
|
String(LuaString<'lua>),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Reference to a Lua table.
|
2017-05-21 19:50:59 -04:00
|
|
|
Table(LuaTable<'lua>),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Reference to a Lua function (or closure).
|
2017-05-21 19:50:59 -04:00
|
|
|
Function(LuaFunction<'lua>),
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Reference to a Lua thread (or coroutine).
|
2017-05-24 23:13:58 -04:00
|
|
|
Thread(LuaThread<'lua>),
|
2017-06-25 01:47:55 -04:00
|
|
|
/// Reference to a userdata object that holds a custom type which implements
|
|
|
|
/// `LuaUserDataType`. Special builtin userdata types will be represented as
|
|
|
|
/// other `LuaValue` variants.
|
|
|
|
UserData(LuaUserData<'lua>),
|
2017-06-25 02:40:09 -04:00
|
|
|
/// `LuaError` is a special builtin userdata type. When received from Lua
|
|
|
|
/// it is implicitly cloned.
|
2017-06-25 02:04:14 -04:00
|
|
|
Error(LuaError),
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
pub use self::LuaValue::Nil as LuaNil;
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Trait for types convertible to `LuaValue`.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub trait ToLua<'a> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Performs the conversion.
|
2017-05-21 19:50:59 -04:00
|
|
|
fn to_lua(self, lua: &'a Lua) -> LuaResult<LuaValue<'a>>;
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Trait for types convertible from `LuaValue`.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub trait FromLua<'a>: Sized {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Performs the conversion.
|
2017-05-21 19:50:59 -04:00
|
|
|
fn from_lua(lua_value: LuaValue<'a>, lua: &'a Lua) -> LuaResult<Self>;
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Multiple Lua values used for both argument passing and also for multiple return values.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct LuaMultiValue<'lua>(VecDeque<LuaValue<'lua>>);
|
|
|
|
|
|
|
|
impl<'lua> LuaMultiValue<'lua> {
|
|
|
|
pub fn new() -> LuaMultiValue<'lua> {
|
|
|
|
LuaMultiValue(VecDeque::new())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> FromIterator<LuaValue<'lua>> for LuaMultiValue<'lua> {
|
|
|
|
fn from_iter<I: IntoIterator<Item = LuaValue<'lua>>>(iter: I) -> Self {
|
|
|
|
LuaMultiValue(VecDeque::from_iter(iter))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> IntoIterator for LuaMultiValue<'lua> {
|
|
|
|
type Item = LuaValue<'lua>;
|
|
|
|
type IntoIter = <VecDeque<LuaValue<'lua>> as IntoIterator>::IntoIter;
|
|
|
|
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
|
|
self.0.into_iter()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> Deref for LuaMultiValue<'lua> {
|
|
|
|
type Target = VecDeque<LuaValue<'lua>>;
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> DerefMut for LuaMultiValue<'lua> {
|
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
&mut self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Trait for types convertible to any number of Lua values.
|
|
|
|
///
|
2017-06-27 14:05:49 -04:00
|
|
|
/// This is a generalization of `ToLua`, allowing any number of resulting Lua values instead of just
|
|
|
|
/// one. Any type that implements `ToLua` will automatically implement this trait.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub trait ToLuaMulti<'a> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Performs the conversion.
|
2017-05-21 19:50:59 -04:00
|
|
|
fn to_lua_multi(self, lua: &'a Lua) -> LuaResult<LuaMultiValue<'a>>;
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Trait for types that can be created from an arbitrary number of Lua values.
|
|
|
|
///
|
2017-06-27 14:05:49 -04:00
|
|
|
/// This is a generalization of `FromLua`, allowing an arbitrary number of Lua values to participate
|
|
|
|
/// in the conversion. Any type that implements `FromLua` will automatically implement this trait.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub trait FromLuaMulti<'a>: Sized {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Performs the conversion.
|
|
|
|
///
|
2017-06-27 14:05:49 -04:00
|
|
|
/// In case `values` contains more values than needed to perform the conversion, the excess
|
|
|
|
/// values should be ignored. This reflects the semantics of Lua when calling a function or
|
|
|
|
/// assigning values. Similarly, if not enough values are given, conversions should assume that
|
|
|
|
/// any missing values are nil.
|
2017-05-21 19:50:59 -04:00
|
|
|
fn from_lua_multi(values: LuaMultiValue<'a>, lua: &'a Lua) -> LuaResult<Self>;
|
|
|
|
}
|
|
|
|
|
2017-07-19 21:32:54 -04:00
|
|
|
type LuaCallback<'lua> = Box<
|
|
|
|
FnMut(&'lua Lua, LuaMultiValue<'lua>) -> LuaResult<LuaMultiValue<'lua>>
|
|
|
|
+ 'lua,
|
|
|
|
>;
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
struct LuaRef<'lua> {
|
|
|
|
lua: &'lua Lua,
|
|
|
|
registry_id: c_int,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> fmt::Debug for LuaRef<'lua> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "LuaRef({})", self.registry_id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> Clone for LuaRef<'lua> {
|
|
|
|
fn clone(&self) -> Self {
|
2017-05-25 00:43:35 -04:00
|
|
|
unsafe {
|
|
|
|
self.lua.push_ref(self.lua.state, self);
|
|
|
|
self.lua.pop_ref(self.lua.state)
|
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> Drop for LuaRef<'lua> {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
ffi::luaL_unref(self.lua.state, ffi::LUA_REGISTRYINDEX, self.registry_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Type of Lua integer numbers.
|
2017-05-25 00:43:35 -04:00
|
|
|
pub type LuaInteger = ffi::lua_Integer;
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Type of Lua floating point numbers.
|
2017-05-25 00:43:35 -04:00
|
|
|
pub type LuaNumber = ffi::lua_Number;
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// A "light" userdata value. Equivalent to an unmanaged raw pointer.
|
2017-05-25 00:43:35 -04:00
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
2017-07-19 20:15:46 -04:00
|
|
|
pub struct LuaLightUserData(pub *mut c_void);
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Handle to an internal Lua string.
|
|
|
|
///
|
|
|
|
/// Unlike Rust strings, Lua strings may not be valid UTF-8.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct LuaString<'lua>(LuaRef<'lua>);
|
|
|
|
|
|
|
|
impl<'lua> LuaString<'lua> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Get a `&str` slice if the Lua string is valid UTF-8.
|
2017-06-22 04:49:18 -04:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # extern crate rlua;
|
|
|
|
/// # use rlua::*;
|
|
|
|
/// # fn main() {
|
|
|
|
/// let lua = Lua::new();
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
/// let globals = lua.globals();
|
2017-06-22 04:49:18 -04:00
|
|
|
///
|
|
|
|
/// let version: LuaString = globals.get("_VERSION").unwrap();
|
|
|
|
/// assert!(version.to_str().unwrap().contains("Lua"));
|
|
|
|
///
|
2017-07-16 16:53:32 -04:00
|
|
|
/// let non_utf8: LuaString = lua.eval(r#" "test\xff" "#, None).unwrap();
|
2017-06-22 04:49:18 -04:00
|
|
|
/// assert!(non_utf8.to_str().is_err());
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2017-06-18 08:48:45 -04:00
|
|
|
pub fn to_str(&self) -> LuaResult<&str> {
|
2017-05-21 19:50:59 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
stack_err_guard(lua.state, 0, || {
|
|
|
|
check_stack(lua.state, 1);
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-05-21 19:50:59 -04:00
|
|
|
assert_eq!(ffi::lua_type(lua.state, -1), ffi::LUA_TSTRING);
|
Big API incompatible error change, remove dependency on error_chain
The current situation with error_chain is less than ideal, and there are lots of
conflicting interests that are impossible to meet at once. Here is an
unorganized brain dump of the current situation, stay awhile and listen!
This change was triggered ultimately by the desire to make LuaError implement
Clone, and this is currently impossible with error_chain. LuaError must
implement Clone to be a proper lua citizen that can live as userdata within a
lua runtime, because there is no way to limit what the lua runtime can do with a
received error. Currently, this is solved by there being a rule that the error
will "expire" if the error is passed back into rust, and this is very
sub-optimal. In fact, one could easily imagine a scenario where lua is for
example memoizing some function, and if the function has ever errored in the
past the function should continue returning the same error, and this situation
immediately fails with this restriciton in place.
Additionally, there are other more minor problems with error_chain which make
the API less good than it could be, or limit how we can use error_chain. This
change has already solved a small bug in a Chucklefish project, where the
conversion from an external error type (Borrow[Mut]Error) was allowed but not
intended for user code, and was accidentally used. Additionally, pattern
matching on error_chain errors, which should be common when dealing with Lua, is
less convenient than a hand rolled error type.
So, if we decide not to use error_chain, we now have a new set of problems if we
decide interoperability with error_chain is important. The first problem we run
into is that there are two natural bounds for wrapped errors that we would
pick, (Error + Send + Sync), or just Error, and neither of them will
interoperate well with error_chain. (Error + Send + Sync) means we can't wrap
error chain errors into LuaError::ExternalError (they're missing the Sync
bound), and having the bounds be just Error means the opposite, that we can't
hold a LuaError inside an error_chain error.
We could just decide that interoperability with error_chain is the most
important qualification, and pick (Error + Send), but this causes a DIFFERENT
set of problems. The rust ecosystem has the two primary error bounds as Error
or (Error + Send + Sync), and there are Into impls from &str / String to
Box<Error + Send + Sync> for example, but NOT (Error + Send). This means that
we are forced to manually recreate the conversions from &str / String to
LuaError rather than relying on a single Into<Box<Error + Send + Sync>> bound,
but this means that string conversions have a different set of methods than
other error types for external error conversion. I have not been able to figure
out an API that I am happy with that uses the (Error + Send) bound. Box<Error>
is obnoxious because not having errors implement Send causes needless problems
in a multithreaded context, so that leaves (Error + Send + Sync). This is
actually a completely reasonable bound for external errors, and has the nice
String Into impls that we would want, the ONLY problem is that it is a pain to
interoperate with the current version of error_chain.
It would be nice to be able to specify the traits that an error generated by the
error_chain macro would implement, and this is apparently in progress in the
error_chain library. This would solve both the problem with not being able to
implement Clone and the problems with (Error + Send) bounds. I am not convinced
that this library should go back to using error_chain when that functionality is
in stable error_chain though, because of the other minor usability problems with
using error_chain.
In that theoretical situation, the downside of NOT using error_chain is simply
that there would not be automatic stacktraces of LuaError. This is not a huge
problem, because stack traces of lua errors are not extremely useful, and for
external errors it is not too hard to create a different version of the
LuaExternalResult / LuaExternalError traits and do conversion from an
error_chain type into a type that will print the stacktrace on display, or
use downcasting in the error causes.
So in summary, this library is no longer using error_chain, and probably will
not use it again in the future. Currently this means that to interoperate with
error_chain, you should use error_chain 0.8.1, which derives Sync on errors, or
wait for a version that supports user defined trait derives. In the future
when error_chain supports user defined trait derives, users may have to take an
extra step to make wrapped external errors print the stacktrace that they
capture.
This change works, but is not entirely complete. There is no error
documentation yet, and the change brought to a head an ugly module organization
problem. There will be more commits for documentation and reorganization, then
a new stable version of rlua.
2017-06-24 18:11:56 -04:00
|
|
|
let s = CStr::from_ptr(ffi::lua_tostring(lua.state, -1))
|
|
|
|
.to_str()
|
2017-06-25 04:25:48 -04:00
|
|
|
.map_err(|e| LuaError::FromLuaConversionError(e.to_string()))?;
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_pop(lua.state, 1);
|
|
|
|
Ok(s)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Handle to an internal Lua table.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct LuaTable<'lua>(LuaRef<'lua>);
|
|
|
|
|
|
|
|
impl<'lua> LuaTable<'lua> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Sets a key-value pair in the table.
|
|
|
|
///
|
|
|
|
/// If the value is `nil`, this will effectively remove the pair.
|
|
|
|
///
|
2017-06-27 14:05:49 -04:00
|
|
|
/// This might invoke the `__newindex` metamethod. Use the `raw_set` method if that is not
|
|
|
|
/// desired.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn set<K: ToLua<'lua>, V: ToLua<'lua>>(&self, key: K, value: V) -> LuaResult<()> {
|
|
|
|
let lua = self.0.lua;
|
2017-06-05 00:41:48 -04:00
|
|
|
let key = key.to_lua(lua)?;
|
|
|
|
let value = value.to_lua(lua)?;
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe {
|
2017-07-23 02:08:32 -04:00
|
|
|
check_stack(lua.state, 5);
|
2017-06-25 02:04:14 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
|
|
|
lua.push_value(lua.state, key);
|
|
|
|
lua.push_value(lua.state, value);
|
2017-07-23 02:08:32 -04:00
|
|
|
error_guard(lua.state, 3, |state| {
|
2017-06-05 00:41:48 -04:00
|
|
|
ffi::lua_settable(state, -3);
|
2017-07-23 02:08:32 -04:00
|
|
|
ffi::lua_pop(state, 1);
|
2017-06-05 00:03:39 -04:00
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Gets the value associated to `key` from the table.
|
|
|
|
///
|
|
|
|
/// If no value is associated to `key`, returns the `nil` value.
|
|
|
|
///
|
2017-06-27 14:05:49 -04:00
|
|
|
/// This might invoke the `__index` metamethod. Use the `raw_get` method if that is not desired.
|
2017-06-05 00:41:48 -04:00
|
|
|
pub fn get<K: ToLua<'lua>, V: FromLua<'lua>>(&self, key: K) -> LuaResult<V> {
|
|
|
|
let lua = self.0.lua;
|
|
|
|
let key = key.to_lua(lua)?;
|
|
|
|
unsafe {
|
2017-07-23 02:08:32 -04:00
|
|
|
check_stack(lua.state, 4);
|
2017-06-25 02:04:14 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
|
|
|
lua.push_value(lua.state, key.to_lua(lua)?);
|
2017-07-23 02:08:32 -04:00
|
|
|
error_guard(lua.state, 2, |state| {
|
2017-06-05 00:41:48 -04:00
|
|
|
ffi::lua_gettable(state, -2);
|
2017-07-23 02:08:32 -04:00
|
|
|
Ok(())
|
2017-06-05 00:41:48 -04:00
|
|
|
})?;
|
2017-07-23 02:08:32 -04:00
|
|
|
let res = lua.pop_value(lua.state);
|
|
|
|
ffi::lua_pop(lua.state, 1);
|
2017-06-05 00:41:48 -04:00
|
|
|
V::from_lua(res, lua)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Checks whether the table contains a non-nil value for `key`.
|
2017-06-18 08:39:18 -04:00
|
|
|
pub fn contains_key<K: ToLua<'lua>>(&self, key: K) -> LuaResult<bool> {
|
2017-06-11 01:12:25 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
let key = key.to_lua(lua)?;
|
|
|
|
unsafe {
|
2017-07-23 02:08:32 -04:00
|
|
|
check_stack(lua.state, 4);
|
2017-06-25 02:04:14 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
|
|
|
lua.push_value(lua.state, key);
|
2017-07-23 02:08:32 -04:00
|
|
|
error_guard(lua.state, 2, |state| {
|
2017-06-11 01:12:25 -04:00
|
|
|
ffi::lua_gettable(state, -2);
|
2017-07-23 02:08:32 -04:00
|
|
|
Ok(())
|
|
|
|
})?;
|
|
|
|
let has = ffi::lua_isnil(lua.state, -1) == 0;
|
|
|
|
ffi::lua_pop(lua.state, 2);
|
|
|
|
Ok(has)
|
2017-06-11 01:12:25 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Sets a key-value pair without invoking metamethods.
|
2017-06-05 00:03:39 -04:00
|
|
|
pub fn raw_set<K: ToLua<'lua>, V: ToLua<'lua>>(&self, key: K, value: V) -> LuaResult<()> {
|
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
stack_err_guard(lua.state, 0, || {
|
|
|
|
check_stack(lua.state, 3);
|
2017-06-05 00:03:39 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(lua.state, key.to_lua(lua)?);
|
|
|
|
lua.push_value(lua.state, value.to_lua(lua)?);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(lua.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_pop(lua.state, 1);
|
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Gets the value associated to `key` without invoking metamethods.
|
2017-06-05 00:41:48 -04:00
|
|
|
pub fn raw_get<K: ToLua<'lua>, V: FromLua<'lua>>(&self, key: K) -> LuaResult<V> {
|
2017-06-05 00:03:39 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
stack_err_guard(lua.state, 0, || {
|
|
|
|
check_stack(lua.state, 2);
|
2017-06-05 00:03:39 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(lua.state, key.to_lua(lua)?);
|
2017-06-05 00:41:48 -04:00
|
|
|
ffi::lua_gettable(lua.state, -2);
|
2017-06-19 02:57:03 -04:00
|
|
|
let res = V::from_lua(lua.pop_value(lua.state), lua)?;
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_pop(lua.state, 1);
|
|
|
|
Ok(res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Returns the result of the Lua `#` operator.
|
|
|
|
///
|
2017-06-27 14:05:49 -04:00
|
|
|
/// This might invoke the `__len` metamethod. Use the `raw_len` method if that is not desired.
|
2017-06-18 08:36:30 -04:00
|
|
|
pub fn len(&self) -> LuaResult<LuaInteger> {
|
2017-05-21 19:50:59 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
2017-07-23 02:08:32 -04:00
|
|
|
check_stack(lua.state, 3);
|
|
|
|
lua.push_ref(lua.state, &self.0);
|
|
|
|
error_guard(lua.state, 1, |state| {
|
|
|
|
let len = ffi::luaL_len(state, -1);
|
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
Ok(len)
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-27 14:05:49 -04:00
|
|
|
/// Returns the result of the Lua `#` operator, without invoking the `__len` metamethod.
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
pub fn raw_len(&self) -> LuaInteger {
|
2017-05-21 19:50:59 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
|
|
|
stack_guard(lua.state, 0, || {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(lua.state, 1);
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-06-05 00:41:48 -04:00
|
|
|
let len = ffi::lua_rawlen(lua.state, -1);
|
|
|
|
ffi::lua_pop(lua.state, 1);
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
len as LuaInteger
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-27 14:05:49 -04:00
|
|
|
/// Consume this table and return an iterator over the pairs of the table, works like the Lua
|
|
|
|
/// 'pairs' function.
|
2017-06-19 02:57:03 -04:00
|
|
|
pub fn pairs<K: FromLua<'lua>, V: FromLua<'lua>>(self) -> LuaTablePairs<'lua, K, V> {
|
|
|
|
let next_key = Some(LuaRef {
|
|
|
|
lua: self.0.lua,
|
|
|
|
registry_id: ffi::LUA_REFNIL,
|
|
|
|
});
|
|
|
|
|
|
|
|
LuaTablePairs {
|
|
|
|
table: self.0,
|
|
|
|
next_key,
|
|
|
|
_phantom: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-27 14:05:49 -04:00
|
|
|
/// Consume this table and return an iterator over the values of this table, which should be a
|
|
|
|
/// sequence. Works like the Lua 'ipairs' function, but doesn't return the indexes, only the
|
|
|
|
/// values in order.
|
2017-06-20 19:04:25 -04:00
|
|
|
pub fn sequence_values<V: FromLua<'lua>>(self) -> LuaTableSequence<'lua, V> {
|
|
|
|
LuaTableSequence {
|
2017-06-19 02:57:03 -04:00
|
|
|
table: self.0,
|
|
|
|
index: Some(1),
|
|
|
|
_phantom: PhantomData,
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
/// An iterator over the pairs of a Lua table.
|
|
|
|
///
|
2017-06-27 14:05:49 -04:00
|
|
|
/// Should behave exactly like the lua 'pairs' function. Holds an internal reference to the table.
|
2017-06-19 02:57:03 -04:00
|
|
|
pub struct LuaTablePairs<'lua, K, V> {
|
|
|
|
table: LuaRef<'lua>,
|
|
|
|
next_key: Option<LuaRef<'lua>>,
|
|
|
|
_phantom: PhantomData<(K, V)>,
|
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
impl<'lua, K, V> Iterator for LuaTablePairs<'lua, K, V>
|
|
|
|
where
|
|
|
|
K: FromLua<'lua>,
|
|
|
|
V: FromLua<'lua>,
|
|
|
|
{
|
|
|
|
type Item = LuaResult<(K, V)>;
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
if let Some(next_key) = self.next_key.take() {
|
|
|
|
let lua = self.table.lua;
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
unsafe {
|
2017-07-23 02:08:32 -04:00
|
|
|
check_stack(lua.state, 6);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_ref(lua.state, &self.table);
|
|
|
|
lua.push_ref(lua.state, &next_key);
|
|
|
|
|
2017-07-23 02:08:32 -04:00
|
|
|
match error_guard(lua.state, 2, |state| Ok(ffi::lua_next(state, -2) != 0)) {
|
|
|
|
Ok(true) => {
|
|
|
|
ffi::lua_pushvalue(lua.state, -2);
|
|
|
|
let key = lua.pop_value(lua.state);
|
|
|
|
let value = lua.pop_value(lua.state);
|
|
|
|
self.next_key = Some(lua.pop_ref(lua.state));
|
|
|
|
ffi::lua_pop(lua.state, 1);
|
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
Some((|| {
|
2017-07-23 02:08:32 -04:00
|
|
|
let key = K::from_lua(key, lua)?;
|
|
|
|
let value = V::from_lua(value, lua)?;
|
|
|
|
Ok((key, value))
|
|
|
|
})())
|
|
|
|
}
|
|
|
|
Ok(false) => {
|
|
|
|
ffi::lua_pop(lua.state, 1);
|
|
|
|
None
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
2017-06-19 02:57:03 -04:00
|
|
|
Err(e) => Some(Err(e)),
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-26 23:49:12 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
/// An iterator over the sequence part of a Lua table.
|
|
|
|
///
|
2017-06-27 14:05:49 -04:00
|
|
|
/// Should behave similarly to the lua 'ipairs" function, except only produces the values, not the
|
|
|
|
/// indexes. Holds an internal reference to the table.
|
2017-06-20 19:04:25 -04:00
|
|
|
pub struct LuaTableSequence<'lua, V> {
|
2017-06-19 02:57:03 -04:00
|
|
|
table: LuaRef<'lua>,
|
|
|
|
index: Option<LuaInteger>,
|
|
|
|
_phantom: PhantomData<V>,
|
|
|
|
}
|
|
|
|
|
2017-06-20 19:04:25 -04:00
|
|
|
impl<'lua, V> Iterator for LuaTableSequence<'lua, V>
|
2017-06-19 02:57:03 -04:00
|
|
|
where
|
|
|
|
V: FromLua<'lua>,
|
|
|
|
{
|
|
|
|
type Item = LuaResult<V>;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
if let Some(index) = self.index.take() {
|
|
|
|
let lua = self.table.lua;
|
|
|
|
|
|
|
|
unsafe {
|
2017-07-23 02:08:32 -04:00
|
|
|
check_stack(lua.state, 4);
|
2017-05-26 23:49:12 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_ref(lua.state, &self.table);
|
2017-07-23 02:08:32 -04:00
|
|
|
match error_guard(lua.state, 1, |state| Ok(ffi::lua_geti(state, -1, index) != ffi::LUA_TNIL)) {
|
|
|
|
Ok(true) => {
|
|
|
|
let value = lua.pop_value(lua.state);
|
|
|
|
ffi::lua_pop(lua.state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
self.index = Some(index + 1);
|
2017-07-23 02:08:32 -04:00
|
|
|
Some(V::from_lua(value, lua))
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-07-23 02:08:32 -04:00
|
|
|
Ok(false) => {
|
|
|
|
ffi::lua_pop(lua.state, 2);
|
|
|
|
None
|
|
|
|
},
|
2017-06-19 02:57:03 -04:00
|
|
|
Err(e) => Some(Err(e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2017-05-26 23:49:12 -04:00
|
|
|
}
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Handle to an internal Lua function.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct LuaFunction<'lua>(LuaRef<'lua>);
|
|
|
|
|
|
|
|
impl<'lua> LuaFunction<'lua> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Calls the function, passing `args` as function arguments.
|
|
|
|
///
|
|
|
|
/// The function's return values are converted to the generic type `R`.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn call<A: ToLuaMulti<'lua>, R: FromLuaMulti<'lua>>(&self, args: A) -> LuaResult<R> {
|
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
stack_err_guard(lua.state, 0, || {
|
2017-05-21 19:50:59 -04:00
|
|
|
let args = args.to_lua_multi(lua)?;
|
|
|
|
let nargs = args.len() as c_int;
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(lua.state, nargs + 3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
let stack_start = ffi::lua_gettop(lua.state);
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-05-21 19:50:59 -04:00
|
|
|
for arg in args {
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(lua.state, arg);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
2017-06-15 10:26:39 -04:00
|
|
|
handle_error(
|
|
|
|
lua.state,
|
|
|
|
pcall_with_traceback(lua.state, nargs, ffi::LUA_MULTRET),
|
|
|
|
)?;
|
2017-05-21 19:50:59 -04:00
|
|
|
let nresults = ffi::lua_gettop(lua.state) - stack_start;
|
|
|
|
let mut results = LuaMultiValue::new();
|
|
|
|
for _ in 0..nresults {
|
2017-06-19 02:57:03 -04:00
|
|
|
results.push_front(lua.pop_value(lua.state));
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
R::from_lua_multi(results, lua)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Returns a function that, when called with no arguments, calls `self`, passing `args` as
|
|
|
|
/// arguments.
|
|
|
|
///
|
|
|
|
/// This is equivalent to this Lua code:
|
|
|
|
///
|
|
|
|
/// ```notrust
|
|
|
|
/// function bind(f, ...)
|
|
|
|
/// return function() f(...) end
|
|
|
|
/// end
|
|
|
|
/// ```
|
2017-06-21 18:38:08 -04:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # extern crate rlua;
|
|
|
|
/// # use rlua::*;
|
|
|
|
///
|
|
|
|
/// # fn main() {
|
|
|
|
/// let lua = Lua::new();
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
/// let globals = lua.globals();
|
2017-06-21 18:38:08 -04:00
|
|
|
///
|
|
|
|
/// // Bind the argument `123` to Lua's `tostring` function
|
|
|
|
/// let tostring: LuaFunction = globals.get("tostring").unwrap();
|
|
|
|
/// let tostring_123: LuaFunction = tostring.bind(123i32).unwrap();
|
|
|
|
///
|
|
|
|
/// // Now we can call `tostring_123` without arguments to get the result of `tostring(123)`
|
|
|
|
/// let result: String = tostring_123.call(()).unwrap();
|
|
|
|
/// assert_eq!(result, "123");
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn bind<A: ToLuaMulti<'lua>>(&self, args: A) -> LuaResult<LuaFunction<'lua>> {
|
|
|
|
unsafe extern "C" fn bind_call_impl(state: *mut ffi::lua_State) -> c_int {
|
|
|
|
let nargs = ffi::lua_gettop(state);
|
|
|
|
|
|
|
|
let nbinds = ffi::lua_tointeger(state, ffi::lua_upvalueindex(2)) as c_int;
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(state, nbinds + 1);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(1));
|
|
|
|
ffi::lua_insert(state, 1);
|
|
|
|
|
|
|
|
// TODO: This is quadratic
|
|
|
|
for i in 0..nbinds {
|
|
|
|
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(i + 3));
|
|
|
|
ffi::lua_insert(state, i + 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
ffi::lua_call(state, nargs + nbinds, ffi::LUA_MULTRET);
|
|
|
|
ffi::lua_gettop(state)
|
|
|
|
}
|
|
|
|
|
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
stack_err_guard(lua.state, 0, || {
|
2017-05-21 19:50:59 -04:00
|
|
|
let args = args.to_lua_multi(lua)?;
|
|
|
|
let nargs = args.len() as c_int;
|
|
|
|
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(lua.state, nargs + 2);
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_pushinteger(lua.state, nargs as ffi::lua_Integer);
|
|
|
|
for arg in args {
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(lua.state, arg);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ffi::lua_pushcclosure(lua.state, bind_call_impl, nargs + 2);
|
|
|
|
|
2017-05-25 00:43:35 -04:00
|
|
|
Ok(LuaFunction(lua.pop_ref(lua.state)))
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Status of a Lua thread (or coroutine).
|
|
|
|
///
|
2017-06-27 14:05:49 -04:00
|
|
|
/// A `LuaThread` is `Active` before the coroutine function finishes, Dead after it finishes, and in
|
|
|
|
/// Error state if error has been called inside the coroutine.
|
2017-05-24 23:13:58 -04:00
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
|
|
|
pub enum LuaThreadStatus {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The thread has finished executing.
|
2017-05-24 23:13:58 -04:00
|
|
|
Dead,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The thread is currently running or suspended because it has called `coroutine.yield`.
|
2017-05-24 23:13:58 -04:00
|
|
|
Active,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The thread has thrown an error during execution.
|
2017-05-24 23:13:58 -04:00
|
|
|
Error,
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Handle to an internal Lua thread (or coroutine).
|
2017-05-24 23:13:58 -04:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct LuaThread<'lua>(LuaRef<'lua>);
|
|
|
|
|
|
|
|
impl<'lua> LuaThread<'lua> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Resumes execution of this thread.
|
|
|
|
///
|
|
|
|
/// Equivalent to `coroutine.resume`.
|
|
|
|
///
|
|
|
|
/// Passes `args` as arguments to the thread. If the coroutine has called `coroutine.yield`, it
|
|
|
|
/// will return these arguments. Otherwise, the coroutine wasn't yet started, so the arguments
|
|
|
|
/// are passed to its main function.
|
|
|
|
///
|
|
|
|
/// If the thread is no longer in `Active` state (meaning it has finished execution or
|
2017-06-27 14:05:49 -04:00
|
|
|
/// encountered an error), this will return Err(CoroutineInactive), otherwise will return Ok as
|
|
|
|
/// follows:
|
2017-06-17 21:23:17 -04:00
|
|
|
///
|
|
|
|
/// If the thread calls `coroutine.yield`, returns the values passed to `yield`. If the thread
|
|
|
|
/// `return`s values from its main function, returns those.
|
2017-06-21 18:27:26 -04:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # extern crate rlua;
|
|
|
|
/// # use rlua::*;
|
|
|
|
///
|
|
|
|
/// # fn main() {
|
|
|
|
/// let lua = Lua::new();
|
|
|
|
/// let thread: LuaThread = lua.eval(r#"
|
|
|
|
/// coroutine.create(function(arg)
|
|
|
|
/// assert(arg == 42)
|
|
|
|
/// local yieldarg = coroutine.yield(123)
|
|
|
|
/// assert(yieldarg == 43)
|
|
|
|
/// return 987
|
|
|
|
/// end)
|
2017-07-16 16:53:32 -04:00
|
|
|
/// "#, None).unwrap();
|
2017-06-21 18:27:26 -04:00
|
|
|
///
|
|
|
|
/// assert_eq!(thread.resume::<_, u32>(42).unwrap(), 123);
|
|
|
|
/// assert_eq!(thread.resume::<_, u32>(43).unwrap(), 987);
|
|
|
|
///
|
|
|
|
/// // The coroutine has now returned, so `resume` will fail
|
|
|
|
/// match thread.resume::<_, u32>(()) {
|
Big API incompatible error change, remove dependency on error_chain
The current situation with error_chain is less than ideal, and there are lots of
conflicting interests that are impossible to meet at once. Here is an
unorganized brain dump of the current situation, stay awhile and listen!
This change was triggered ultimately by the desire to make LuaError implement
Clone, and this is currently impossible with error_chain. LuaError must
implement Clone to be a proper lua citizen that can live as userdata within a
lua runtime, because there is no way to limit what the lua runtime can do with a
received error. Currently, this is solved by there being a rule that the error
will "expire" if the error is passed back into rust, and this is very
sub-optimal. In fact, one could easily imagine a scenario where lua is for
example memoizing some function, and if the function has ever errored in the
past the function should continue returning the same error, and this situation
immediately fails with this restriciton in place.
Additionally, there are other more minor problems with error_chain which make
the API less good than it could be, or limit how we can use error_chain. This
change has already solved a small bug in a Chucklefish project, where the
conversion from an external error type (Borrow[Mut]Error) was allowed but not
intended for user code, and was accidentally used. Additionally, pattern
matching on error_chain errors, which should be common when dealing with Lua, is
less convenient than a hand rolled error type.
So, if we decide not to use error_chain, we now have a new set of problems if we
decide interoperability with error_chain is important. The first problem we run
into is that there are two natural bounds for wrapped errors that we would
pick, (Error + Send + Sync), or just Error, and neither of them will
interoperate well with error_chain. (Error + Send + Sync) means we can't wrap
error chain errors into LuaError::ExternalError (they're missing the Sync
bound), and having the bounds be just Error means the opposite, that we can't
hold a LuaError inside an error_chain error.
We could just decide that interoperability with error_chain is the most
important qualification, and pick (Error + Send), but this causes a DIFFERENT
set of problems. The rust ecosystem has the two primary error bounds as Error
or (Error + Send + Sync), and there are Into impls from &str / String to
Box<Error + Send + Sync> for example, but NOT (Error + Send). This means that
we are forced to manually recreate the conversions from &str / String to
LuaError rather than relying on a single Into<Box<Error + Send + Sync>> bound,
but this means that string conversions have a different set of methods than
other error types for external error conversion. I have not been able to figure
out an API that I am happy with that uses the (Error + Send) bound. Box<Error>
is obnoxious because not having errors implement Send causes needless problems
in a multithreaded context, so that leaves (Error + Send + Sync). This is
actually a completely reasonable bound for external errors, and has the nice
String Into impls that we would want, the ONLY problem is that it is a pain to
interoperate with the current version of error_chain.
It would be nice to be able to specify the traits that an error generated by the
error_chain macro would implement, and this is apparently in progress in the
error_chain library. This would solve both the problem with not being able to
implement Clone and the problems with (Error + Send) bounds. I am not convinced
that this library should go back to using error_chain when that functionality is
in stable error_chain though, because of the other minor usability problems with
using error_chain.
In that theoretical situation, the downside of NOT using error_chain is simply
that there would not be automatic stacktraces of LuaError. This is not a huge
problem, because stack traces of lua errors are not extremely useful, and for
external errors it is not too hard to create a different version of the
LuaExternalResult / LuaExternalError traits and do conversion from an
error_chain type into a type that will print the stacktrace on display, or
use downcasting in the error causes.
So in summary, this library is no longer using error_chain, and probably will
not use it again in the future. Currently this means that to interoperate with
error_chain, you should use error_chain 0.8.1, which derives Sync on errors, or
wait for a version that supports user defined trait derives. In the future
when error_chain supports user defined trait derives, users may have to take an
extra step to make wrapped external errors print the stacktrace that they
capture.
This change works, but is not entirely complete. There is no error
documentation yet, and the change brought to a head an ugly module organization
problem. There will be more commits for documentation and reorganization, then
a new stable version of rlua.
2017-06-24 18:11:56 -04:00
|
|
|
/// Err(LuaError::CoroutineInactive) => {},
|
2017-06-21 18:27:26 -04:00
|
|
|
/// unexpected => panic!("unexpected result {:?}", unexpected),
|
|
|
|
/// }
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2017-06-17 23:50:40 -04:00
|
|
|
pub fn resume<A, R>(&self, args: A) -> LuaResult<R>
|
|
|
|
where
|
|
|
|
A: ToLuaMulti<'lua>,
|
|
|
|
R: FromLuaMulti<'lua>,
|
|
|
|
{
|
2017-05-24 23:13:58 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
stack_err_guard(lua.state, 0, || {
|
|
|
|
check_stack(lua.state, 1);
|
2017-05-24 23:13:58 -04:00
|
|
|
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-05-24 23:13:58 -04:00
|
|
|
let thread_state = ffi::lua_tothread(lua.state, -1);
|
|
|
|
|
2017-06-17 22:40:09 -04:00
|
|
|
let status = ffi::lua_status(thread_state);
|
2017-06-17 23:50:40 -04:00
|
|
|
if status != ffi::LUA_YIELD && ffi::lua_gettop(thread_state) == 0 {
|
Big API incompatible error change, remove dependency on error_chain
The current situation with error_chain is less than ideal, and there are lots of
conflicting interests that are impossible to meet at once. Here is an
unorganized brain dump of the current situation, stay awhile and listen!
This change was triggered ultimately by the desire to make LuaError implement
Clone, and this is currently impossible with error_chain. LuaError must
implement Clone to be a proper lua citizen that can live as userdata within a
lua runtime, because there is no way to limit what the lua runtime can do with a
received error. Currently, this is solved by there being a rule that the error
will "expire" if the error is passed back into rust, and this is very
sub-optimal. In fact, one could easily imagine a scenario where lua is for
example memoizing some function, and if the function has ever errored in the
past the function should continue returning the same error, and this situation
immediately fails with this restriciton in place.
Additionally, there are other more minor problems with error_chain which make
the API less good than it could be, or limit how we can use error_chain. This
change has already solved a small bug in a Chucklefish project, where the
conversion from an external error type (Borrow[Mut]Error) was allowed but not
intended for user code, and was accidentally used. Additionally, pattern
matching on error_chain errors, which should be common when dealing with Lua, is
less convenient than a hand rolled error type.
So, if we decide not to use error_chain, we now have a new set of problems if we
decide interoperability with error_chain is important. The first problem we run
into is that there are two natural bounds for wrapped errors that we would
pick, (Error + Send + Sync), or just Error, and neither of them will
interoperate well with error_chain. (Error + Send + Sync) means we can't wrap
error chain errors into LuaError::ExternalError (they're missing the Sync
bound), and having the bounds be just Error means the opposite, that we can't
hold a LuaError inside an error_chain error.
We could just decide that interoperability with error_chain is the most
important qualification, and pick (Error + Send), but this causes a DIFFERENT
set of problems. The rust ecosystem has the two primary error bounds as Error
or (Error + Send + Sync), and there are Into impls from &str / String to
Box<Error + Send + Sync> for example, but NOT (Error + Send). This means that
we are forced to manually recreate the conversions from &str / String to
LuaError rather than relying on a single Into<Box<Error + Send + Sync>> bound,
but this means that string conversions have a different set of methods than
other error types for external error conversion. I have not been able to figure
out an API that I am happy with that uses the (Error + Send) bound. Box<Error>
is obnoxious because not having errors implement Send causes needless problems
in a multithreaded context, so that leaves (Error + Send + Sync). This is
actually a completely reasonable bound for external errors, and has the nice
String Into impls that we would want, the ONLY problem is that it is a pain to
interoperate with the current version of error_chain.
It would be nice to be able to specify the traits that an error generated by the
error_chain macro would implement, and this is apparently in progress in the
error_chain library. This would solve both the problem with not being able to
implement Clone and the problems with (Error + Send) bounds. I am not convinced
that this library should go back to using error_chain when that functionality is
in stable error_chain though, because of the other minor usability problems with
using error_chain.
In that theoretical situation, the downside of NOT using error_chain is simply
that there would not be automatic stacktraces of LuaError. This is not a huge
problem, because stack traces of lua errors are not extremely useful, and for
external errors it is not too hard to create a different version of the
LuaExternalResult / LuaExternalError traits and do conversion from an
error_chain type into a type that will print the stacktrace on display, or
use downcasting in the error causes.
So in summary, this library is no longer using error_chain, and probably will
not use it again in the future. Currently this means that to interoperate with
error_chain, you should use error_chain 0.8.1, which derives Sync on errors, or
wait for a version that supports user defined trait derives. In the future
when error_chain supports user defined trait derives, users may have to take an
extra step to make wrapped external errors print the stacktrace that they
capture.
This change works, but is not entirely complete. There is no error
documentation yet, and the change brought to a head an ugly module organization
problem. There will be more commits for documentation and reorganization, then
a new stable version of rlua.
2017-06-24 18:11:56 -04:00
|
|
|
return Err(LuaError::CoroutineInactive);
|
2017-06-17 23:50:40 -04:00
|
|
|
}
|
2017-05-24 23:13:58 -04:00
|
|
|
|
2017-06-17 23:50:40 -04:00
|
|
|
ffi::lua_pop(lua.state, 1);
|
2017-05-24 23:13:58 -04:00
|
|
|
|
2017-06-17 23:50:40 -04:00
|
|
|
let args = args.to_lua_multi(lua)?;
|
|
|
|
let nargs = args.len() as c_int;
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(thread_state, nargs);
|
2017-05-24 23:13:58 -04:00
|
|
|
|
2017-06-17 23:50:40 -04:00
|
|
|
for arg in args {
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(thread_state, arg);
|
2017-06-17 23:50:40 -04:00
|
|
|
}
|
2017-06-17 22:40:09 -04:00
|
|
|
|
2017-06-17 23:50:40 -04:00
|
|
|
handle_error(
|
|
|
|
lua.state,
|
|
|
|
resume_with_traceback(thread_state, lua.state, nargs),
|
|
|
|
)?;
|
|
|
|
|
|
|
|
let nresults = ffi::lua_gettop(thread_state);
|
|
|
|
let mut results = LuaMultiValue::new();
|
|
|
|
for _ in 0..nresults {
|
2017-06-19 02:57:03 -04:00
|
|
|
results.push_front(lua.pop_value(thread_state));
|
2017-05-24 23:13:58 -04:00
|
|
|
}
|
2017-06-17 23:50:40 -04:00
|
|
|
R::from_lua_multi(results, lua)
|
2017-05-24 23:13:58 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Gets the status of the thread.
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
pub fn status(&self) -> LuaThreadStatus {
|
2017-05-24 23:13:58 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
|
|
|
stack_guard(lua.state, 0, || {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(lua.state, 1);
|
2017-05-24 23:13:58 -04:00
|
|
|
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-05-24 23:13:58 -04:00
|
|
|
let thread_state = ffi::lua_tothread(lua.state, -1);
|
|
|
|
ffi::lua_pop(lua.state, 1);
|
|
|
|
|
|
|
|
let status = ffi::lua_status(thread_state);
|
|
|
|
if status != ffi::LUA_OK && status != ffi::LUA_YIELD {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
LuaThreadStatus::Error
|
2017-05-24 23:13:58 -04:00
|
|
|
} else if status == ffi::LUA_YIELD || ffi::lua_gettop(thread_state) > 0 {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
LuaThreadStatus::Active
|
2017-05-24 23:13:58 -04:00
|
|
|
} else {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
LuaThreadStatus::Dead
|
2017-05-24 23:13:58 -04:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Kinds of metamethods that can be overridden.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
|
|
|
pub enum LuaMetaMethod {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `+` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Add,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `-` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Sub,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `*` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Mul,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `/` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Div,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `%` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Mod,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `^` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Pow,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The unary minus (`-`) operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Unm,
|
2017-06-18 00:28:46 -04:00
|
|
|
/// The floor division (//) operator.
|
|
|
|
IDiv,
|
|
|
|
/// The bitwise AND (&) operator.
|
|
|
|
BAnd,
|
|
|
|
/// The bitwise OR (|) operator.
|
|
|
|
BOr,
|
|
|
|
/// The bitwise XOR (binary ~) operator.
|
|
|
|
BXor,
|
|
|
|
/// The bitwise NOT (unary ~) operator.
|
|
|
|
BNot,
|
|
|
|
/// The bitwise left shift (<<) operator.
|
|
|
|
Shl,
|
|
|
|
/// The bitwise right shift (>>) operator.
|
|
|
|
Shr,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The string concatenation operator `..`.
|
2017-05-21 19:50:59 -04:00
|
|
|
Concat,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The length operator `#`.
|
2017-05-21 19:50:59 -04:00
|
|
|
Len,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `==` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Eq,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `<` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Lt,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The `<=` operator.
|
2017-05-21 19:50:59 -04:00
|
|
|
Le,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Index access `obj[key]`.
|
2017-05-21 19:50:59 -04:00
|
|
|
Index,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Index write access `obj[key] = value`.
|
2017-05-21 19:50:59 -04:00
|
|
|
NewIndex,
|
2017-06-17 21:23:17 -04:00
|
|
|
/// The call "operator" `obj(arg1, args2, ...)`.
|
2017-05-21 19:50:59 -04:00
|
|
|
Call,
|
2017-06-23 15:24:03 -04:00
|
|
|
/// tostring(ud) will call this if it exists
|
|
|
|
ToString,
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Stores methods of a userdata object.
|
|
|
|
///
|
2017-06-27 14:05:49 -04:00
|
|
|
/// Methods added will be added to the `__index` table on the metatable for the userdata, so they
|
|
|
|
/// can be called as `userdata:method(args)` as expected. If there are any regular methods, and an
|
|
|
|
/// `Index` metamethod is given, it will be called as a *fallback* if the index doesn't match an
|
|
|
|
/// existing regular method.
|
2017-07-19 21:28:16 -04:00
|
|
|
pub struct LuaUserDataMethods<'lua, T> {
|
|
|
|
methods: HashMap<String, LuaCallback<'lua>>,
|
|
|
|
meta_methods: HashMap<LuaMetaMethod, LuaCallback<'lua>>,
|
2017-05-21 19:50:59 -04:00
|
|
|
_type: PhantomData<T>,
|
|
|
|
}
|
|
|
|
|
2017-07-19 21:28:16 -04:00
|
|
|
impl<'lua, T: LuaUserDataType> LuaUserDataMethods<'lua, T> {
|
2017-06-27 14:05:49 -04:00
|
|
|
/// Add a regular method as a function which accepts a &T as the first parameter.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn add_method<M>(&mut self, name: &str, method: M)
|
2017-07-19 21:28:16 -04:00
|
|
|
where
|
|
|
|
M: 'lua + for<'a> FnMut(&'lua Lua, &'a T, LuaMultiValue<'lua>) -> LuaResult<LuaMultiValue<'lua>>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
2017-06-15 10:26:39 -04:00
|
|
|
self.methods.insert(
|
|
|
|
name.to_owned(),
|
|
|
|
Self::box_method(method),
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-27 14:05:49 -04:00
|
|
|
/// Add a regular method as a function which accepts a &mut T as the first parameter.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn add_method_mut<M>(&mut self, name: &str, method: M)
|
2017-07-19 21:28:16 -04:00
|
|
|
where M: 'lua + for<'a> FnMut(&'lua Lua, &'a mut T, LuaMultiValue<'lua>)
|
2017-05-21 19:50:59 -04:00
|
|
|
-> LuaResult<LuaMultiValue<'lua>>
|
|
|
|
{
|
2017-06-15 10:26:39 -04:00
|
|
|
self.methods.insert(
|
|
|
|
name.to_owned(),
|
|
|
|
Self::box_method_mut(method),
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-27 14:05:49 -04:00
|
|
|
/// Add a regular method as a function which accepts generic arguments, the first argument will
|
|
|
|
/// always be a LuaUserData of type T.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn add_function<F>(&mut self, name: &str, function: F)
|
2017-07-19 21:28:16 -04:00
|
|
|
where
|
|
|
|
F: 'lua + for<'a> FnMut(&'lua Lua, LuaMultiValue<'lua>) -> LuaResult<LuaMultiValue<'lua>>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
|
|
|
self.methods.insert(name.to_owned(), Box::new(function));
|
|
|
|
}
|
|
|
|
|
2017-06-27 14:05:49 -04:00
|
|
|
/// Add a metamethod as a function which accepts a &T as the first parameter. This can cause an
|
|
|
|
/// error with certain binary metamethods that can trigger if ony the right side has a
|
|
|
|
/// metatable.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn add_meta_method<M>(&mut self, meta: LuaMetaMethod, method: M)
|
2017-07-19 21:28:16 -04:00
|
|
|
where
|
|
|
|
M: 'lua + for<'a> FnMut(&'lua Lua, &'a T, LuaMultiValue<'lua>) -> LuaResult<LuaMultiValue<'lua>>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
|
|
|
self.meta_methods.insert(meta, Self::box_method(method));
|
|
|
|
}
|
|
|
|
|
2017-06-27 14:05:49 -04:00
|
|
|
/// Add a metamethod as a function which accepts a &mut T as the first parameter. This can
|
|
|
|
/// cause an error with certain binary metamethods that can trigger if ony the right side has a
|
|
|
|
/// metatable.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn add_meta_method_mut<M>(&mut self, meta: LuaMetaMethod, method: M)
|
2017-07-19 21:28:16 -04:00
|
|
|
where M: 'lua + for<'a> FnMut(&'lua Lua, &'a mut T, LuaMultiValue<'lua>)
|
2017-05-21 19:50:59 -04:00
|
|
|
-> LuaResult<LuaMultiValue<'lua>>
|
|
|
|
{
|
|
|
|
self.meta_methods.insert(meta, Self::box_method_mut(method));
|
|
|
|
}
|
|
|
|
|
2017-06-27 14:05:49 -04:00
|
|
|
/// Add a metamethod as a function which accepts generic arguments. Metamethods in Lua for
|
|
|
|
/// binary operators can be triggered if either the left or right argument to the binary
|
|
|
|
/// operator has a metatable, so the first argument here is not necessarily a userdata of type
|
|
|
|
/// T.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn add_meta_function<F>(&mut self, meta: LuaMetaMethod, function: F)
|
2017-07-19 21:28:16 -04:00
|
|
|
where
|
|
|
|
F: 'lua + for<'a> FnMut(&'lua Lua, LuaMultiValue<'lua>) -> LuaResult<LuaMultiValue<'lua>>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
|
|
|
self.meta_methods.insert(meta, Box::new(function));
|
|
|
|
}
|
|
|
|
|
2017-07-19 21:28:16 -04:00
|
|
|
fn box_method<M>(mut method: M) -> LuaCallback<'lua>
|
|
|
|
where
|
|
|
|
M: 'lua + for<'a> FnMut(&'lua Lua, &'a T, LuaMultiValue<'lua>) -> LuaResult<LuaMultiValue<'lua>>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
|
|
|
Box::new(move |lua, mut args| if let Some(front) = args.pop_front() {
|
2017-06-15 10:26:39 -04:00
|
|
|
let userdata = LuaUserData::from_lua(front, lua)?;
|
|
|
|
let userdata = userdata.borrow::<T>()?;
|
|
|
|
method(lua, &userdata, args)
|
|
|
|
} else {
|
2017-06-25 04:25:48 -04:00
|
|
|
Err(LuaError::FromLuaConversionError(
|
|
|
|
"No userdata supplied as first argument to method"
|
|
|
|
.to_owned(),
|
|
|
|
))
|
2017-06-15 10:26:39 -04:00
|
|
|
})
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-07-19 21:28:16 -04:00
|
|
|
fn box_method_mut<M>(mut method: M) -> LuaCallback<'lua>
|
|
|
|
where M: 'lua + for<'a> FnMut(&'lua Lua, &'a mut T, LuaMultiValue<'lua>)
|
2017-05-21 19:50:59 -04:00
|
|
|
-> LuaResult<LuaMultiValue<'lua>>
|
|
|
|
{
|
|
|
|
Box::new(move |lua, mut args| if let Some(front) = args.pop_front() {
|
2017-06-15 10:26:39 -04:00
|
|
|
let userdata = LuaUserData::from_lua(front, lua)?;
|
|
|
|
let mut userdata = userdata.borrow_mut::<T>()?;
|
|
|
|
method(lua, &mut userdata, args)
|
|
|
|
} else {
|
2017-06-24 20:57:04 -04:00
|
|
|
Err(
|
2017-06-25 04:25:48 -04:00
|
|
|
LuaError::FromLuaConversionError(
|
2017-06-24 20:57:04 -04:00
|
|
|
"No userdata supplied as first argument to method".to_owned(),
|
|
|
|
).into(),
|
|
|
|
)
|
2017-06-15 10:26:39 -04:00
|
|
|
})
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Trait for custom userdata types.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub trait LuaUserDataType: 'static + Sized {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Adds custom methods and operators specific to this userdata.
|
2017-05-21 19:50:59 -04:00
|
|
|
fn add_methods(_methods: &mut LuaUserDataMethods<Self>) {}
|
|
|
|
}
|
|
|
|
|
2017-07-19 21:28:16 -04:00
|
|
|
/// Handle to an internal Lua userdata for a type that implements `LuaUserDataType`. Internally,
|
2017-06-27 14:05:49 -04:00
|
|
|
/// instances are stored in a `RefCell`, to best match the mutable semantics of the Lua language.
|
2017-05-21 19:50:59 -04:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct LuaUserData<'lua>(LuaRef<'lua>);
|
|
|
|
|
|
|
|
impl<'lua> LuaUserData<'lua> {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Checks whether `T` is the type of this userdata.
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
pub fn is<T: LuaUserDataType>(&self) -> bool {
|
|
|
|
self.inspect(|_: &RefCell<T>| ()).is_some()
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-05-21 22:32:16 -04:00
|
|
|
/// Borrow this userdata out of the internal RefCell that is held in lua.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn borrow<T: LuaUserDataType>(&self) -> LuaResult<Ref<T>> {
|
Big API incompatible error change, remove dependency on error_chain
The current situation with error_chain is less than ideal, and there are lots of
conflicting interests that are impossible to meet at once. Here is an
unorganized brain dump of the current situation, stay awhile and listen!
This change was triggered ultimately by the desire to make LuaError implement
Clone, and this is currently impossible with error_chain. LuaError must
implement Clone to be a proper lua citizen that can live as userdata within a
lua runtime, because there is no way to limit what the lua runtime can do with a
received error. Currently, this is solved by there being a rule that the error
will "expire" if the error is passed back into rust, and this is very
sub-optimal. In fact, one could easily imagine a scenario where lua is for
example memoizing some function, and if the function has ever errored in the
past the function should continue returning the same error, and this situation
immediately fails with this restriciton in place.
Additionally, there are other more minor problems with error_chain which make
the API less good than it could be, or limit how we can use error_chain. This
change has already solved a small bug in a Chucklefish project, where the
conversion from an external error type (Borrow[Mut]Error) was allowed but not
intended for user code, and was accidentally used. Additionally, pattern
matching on error_chain errors, which should be common when dealing with Lua, is
less convenient than a hand rolled error type.
So, if we decide not to use error_chain, we now have a new set of problems if we
decide interoperability with error_chain is important. The first problem we run
into is that there are two natural bounds for wrapped errors that we would
pick, (Error + Send + Sync), or just Error, and neither of them will
interoperate well with error_chain. (Error + Send + Sync) means we can't wrap
error chain errors into LuaError::ExternalError (they're missing the Sync
bound), and having the bounds be just Error means the opposite, that we can't
hold a LuaError inside an error_chain error.
We could just decide that interoperability with error_chain is the most
important qualification, and pick (Error + Send), but this causes a DIFFERENT
set of problems. The rust ecosystem has the two primary error bounds as Error
or (Error + Send + Sync), and there are Into impls from &str / String to
Box<Error + Send + Sync> for example, but NOT (Error + Send). This means that
we are forced to manually recreate the conversions from &str / String to
LuaError rather than relying on a single Into<Box<Error + Send + Sync>> bound,
but this means that string conversions have a different set of methods than
other error types for external error conversion. I have not been able to figure
out an API that I am happy with that uses the (Error + Send) bound. Box<Error>
is obnoxious because not having errors implement Send causes needless problems
in a multithreaded context, so that leaves (Error + Send + Sync). This is
actually a completely reasonable bound for external errors, and has the nice
String Into impls that we would want, the ONLY problem is that it is a pain to
interoperate with the current version of error_chain.
It would be nice to be able to specify the traits that an error generated by the
error_chain macro would implement, and this is apparently in progress in the
error_chain library. This would solve both the problem with not being able to
implement Clone and the problems with (Error + Send) bounds. I am not convinced
that this library should go back to using error_chain when that functionality is
in stable error_chain though, because of the other minor usability problems with
using error_chain.
In that theoretical situation, the downside of NOT using error_chain is simply
that there would not be automatic stacktraces of LuaError. This is not a huge
problem, because stack traces of lua errors are not extremely useful, and for
external errors it is not too hard to create a different version of the
LuaExternalResult / LuaExternalError traits and do conversion from an
error_chain type into a type that will print the stacktrace on display, or
use downcasting in the error causes.
So in summary, this library is no longer using error_chain, and probably will
not use it again in the future. Currently this means that to interoperate with
error_chain, you should use error_chain 0.8.1, which derives Sync on errors, or
wait for a version that supports user defined trait derives. In the future
when error_chain supports user defined trait derives, users may have to take an
extra step to make wrapped external errors print the stacktrace that they
capture.
This change works, but is not entirely complete. There is no error
documentation yet, and the change brought to a head an ugly module organization
problem. There will be more commits for documentation and reorganization, then
a new stable version of rlua.
2017-06-24 18:11:56 -04:00
|
|
|
self.inspect(|cell| {
|
|
|
|
Ok(
|
2017-06-25 04:25:48 -04:00
|
|
|
cell.try_borrow().map_err(|_| LuaError::UserDataBorrowError)?,
|
Big API incompatible error change, remove dependency on error_chain
The current situation with error_chain is less than ideal, and there are lots of
conflicting interests that are impossible to meet at once. Here is an
unorganized brain dump of the current situation, stay awhile and listen!
This change was triggered ultimately by the desire to make LuaError implement
Clone, and this is currently impossible with error_chain. LuaError must
implement Clone to be a proper lua citizen that can live as userdata within a
lua runtime, because there is no way to limit what the lua runtime can do with a
received error. Currently, this is solved by there being a rule that the error
will "expire" if the error is passed back into rust, and this is very
sub-optimal. In fact, one could easily imagine a scenario where lua is for
example memoizing some function, and if the function has ever errored in the
past the function should continue returning the same error, and this situation
immediately fails with this restriciton in place.
Additionally, there are other more minor problems with error_chain which make
the API less good than it could be, or limit how we can use error_chain. This
change has already solved a small bug in a Chucklefish project, where the
conversion from an external error type (Borrow[Mut]Error) was allowed but not
intended for user code, and was accidentally used. Additionally, pattern
matching on error_chain errors, which should be common when dealing with Lua, is
less convenient than a hand rolled error type.
So, if we decide not to use error_chain, we now have a new set of problems if we
decide interoperability with error_chain is important. The first problem we run
into is that there are two natural bounds for wrapped errors that we would
pick, (Error + Send + Sync), or just Error, and neither of them will
interoperate well with error_chain. (Error + Send + Sync) means we can't wrap
error chain errors into LuaError::ExternalError (they're missing the Sync
bound), and having the bounds be just Error means the opposite, that we can't
hold a LuaError inside an error_chain error.
We could just decide that interoperability with error_chain is the most
important qualification, and pick (Error + Send), but this causes a DIFFERENT
set of problems. The rust ecosystem has the two primary error bounds as Error
or (Error + Send + Sync), and there are Into impls from &str / String to
Box<Error + Send + Sync> for example, but NOT (Error + Send). This means that
we are forced to manually recreate the conversions from &str / String to
LuaError rather than relying on a single Into<Box<Error + Send + Sync>> bound,
but this means that string conversions have a different set of methods than
other error types for external error conversion. I have not been able to figure
out an API that I am happy with that uses the (Error + Send) bound. Box<Error>
is obnoxious because not having errors implement Send causes needless problems
in a multithreaded context, so that leaves (Error + Send + Sync). This is
actually a completely reasonable bound for external errors, and has the nice
String Into impls that we would want, the ONLY problem is that it is a pain to
interoperate with the current version of error_chain.
It would be nice to be able to specify the traits that an error generated by the
error_chain macro would implement, and this is apparently in progress in the
error_chain library. This would solve both the problem with not being able to
implement Clone and the problems with (Error + Send) bounds. I am not convinced
that this library should go back to using error_chain when that functionality is
in stable error_chain though, because of the other minor usability problems with
using error_chain.
In that theoretical situation, the downside of NOT using error_chain is simply
that there would not be automatic stacktraces of LuaError. This is not a huge
problem, because stack traces of lua errors are not extremely useful, and for
external errors it is not too hard to create a different version of the
LuaExternalResult / LuaExternalError traits and do conversion from an
error_chain type into a type that will print the stacktrace on display, or
use downcasting in the error causes.
So in summary, this library is no longer using error_chain, and probably will
not use it again in the future. Currently this means that to interoperate with
error_chain, you should use error_chain 0.8.1, which derives Sync on errors, or
wait for a version that supports user defined trait derives. In the future
when error_chain supports user defined trait derives, users may have to take an
extra step to make wrapped external errors print the stacktrace that they
capture.
This change works, but is not entirely complete. There is no error
documentation yet, and the change brought to a head an ugly module organization
problem. There will be more commits for documentation and reorganization, then
a new stable version of rlua.
2017-06-24 18:11:56 -04:00
|
|
|
)
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
}).ok_or(LuaError::UserDataTypeMismatch)?
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-27 14:05:49 -04:00
|
|
|
/// Borrow mutably this userdata out of the internal RefCell that is held in lua.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn borrow_mut<T: LuaUserDataType>(&self) -> LuaResult<RefMut<T>> {
|
Big API incompatible error change, remove dependency on error_chain
The current situation with error_chain is less than ideal, and there are lots of
conflicting interests that are impossible to meet at once. Here is an
unorganized brain dump of the current situation, stay awhile and listen!
This change was triggered ultimately by the desire to make LuaError implement
Clone, and this is currently impossible with error_chain. LuaError must
implement Clone to be a proper lua citizen that can live as userdata within a
lua runtime, because there is no way to limit what the lua runtime can do with a
received error. Currently, this is solved by there being a rule that the error
will "expire" if the error is passed back into rust, and this is very
sub-optimal. In fact, one could easily imagine a scenario where lua is for
example memoizing some function, and if the function has ever errored in the
past the function should continue returning the same error, and this situation
immediately fails with this restriciton in place.
Additionally, there are other more minor problems with error_chain which make
the API less good than it could be, or limit how we can use error_chain. This
change has already solved a small bug in a Chucklefish project, where the
conversion from an external error type (Borrow[Mut]Error) was allowed but not
intended for user code, and was accidentally used. Additionally, pattern
matching on error_chain errors, which should be common when dealing with Lua, is
less convenient than a hand rolled error type.
So, if we decide not to use error_chain, we now have a new set of problems if we
decide interoperability with error_chain is important. The first problem we run
into is that there are two natural bounds for wrapped errors that we would
pick, (Error + Send + Sync), or just Error, and neither of them will
interoperate well with error_chain. (Error + Send + Sync) means we can't wrap
error chain errors into LuaError::ExternalError (they're missing the Sync
bound), and having the bounds be just Error means the opposite, that we can't
hold a LuaError inside an error_chain error.
We could just decide that interoperability with error_chain is the most
important qualification, and pick (Error + Send), but this causes a DIFFERENT
set of problems. The rust ecosystem has the two primary error bounds as Error
or (Error + Send + Sync), and there are Into impls from &str / String to
Box<Error + Send + Sync> for example, but NOT (Error + Send). This means that
we are forced to manually recreate the conversions from &str / String to
LuaError rather than relying on a single Into<Box<Error + Send + Sync>> bound,
but this means that string conversions have a different set of methods than
other error types for external error conversion. I have not been able to figure
out an API that I am happy with that uses the (Error + Send) bound. Box<Error>
is obnoxious because not having errors implement Send causes needless problems
in a multithreaded context, so that leaves (Error + Send + Sync). This is
actually a completely reasonable bound for external errors, and has the nice
String Into impls that we would want, the ONLY problem is that it is a pain to
interoperate with the current version of error_chain.
It would be nice to be able to specify the traits that an error generated by the
error_chain macro would implement, and this is apparently in progress in the
error_chain library. This would solve both the problem with not being able to
implement Clone and the problems with (Error + Send) bounds. I am not convinced
that this library should go back to using error_chain when that functionality is
in stable error_chain though, because of the other minor usability problems with
using error_chain.
In that theoretical situation, the downside of NOT using error_chain is simply
that there would not be automatic stacktraces of LuaError. This is not a huge
problem, because stack traces of lua errors are not extremely useful, and for
external errors it is not too hard to create a different version of the
LuaExternalResult / LuaExternalError traits and do conversion from an
error_chain type into a type that will print the stacktrace on display, or
use downcasting in the error causes.
So in summary, this library is no longer using error_chain, and probably will
not use it again in the future. Currently this means that to interoperate with
error_chain, you should use error_chain 0.8.1, which derives Sync on errors, or
wait for a version that supports user defined trait derives. In the future
when error_chain supports user defined trait derives, users may have to take an
extra step to make wrapped external errors print the stacktrace that they
capture.
This change works, but is not entirely complete. There is no error
documentation yet, and the change brought to a head an ugly module organization
problem. There will be more commits for documentation and reorganization, then
a new stable version of rlua.
2017-06-24 18:11:56 -04:00
|
|
|
self.inspect(|cell| {
|
|
|
|
Ok(cell.try_borrow_mut().map_err(
|
2017-06-25 04:25:48 -04:00
|
|
|
|_| LuaError::UserDataBorrowMutError,
|
Big API incompatible error change, remove dependency on error_chain
The current situation with error_chain is less than ideal, and there are lots of
conflicting interests that are impossible to meet at once. Here is an
unorganized brain dump of the current situation, stay awhile and listen!
This change was triggered ultimately by the desire to make LuaError implement
Clone, and this is currently impossible with error_chain. LuaError must
implement Clone to be a proper lua citizen that can live as userdata within a
lua runtime, because there is no way to limit what the lua runtime can do with a
received error. Currently, this is solved by there being a rule that the error
will "expire" if the error is passed back into rust, and this is very
sub-optimal. In fact, one could easily imagine a scenario where lua is for
example memoizing some function, and if the function has ever errored in the
past the function should continue returning the same error, and this situation
immediately fails with this restriciton in place.
Additionally, there are other more minor problems with error_chain which make
the API less good than it could be, or limit how we can use error_chain. This
change has already solved a small bug in a Chucklefish project, where the
conversion from an external error type (Borrow[Mut]Error) was allowed but not
intended for user code, and was accidentally used. Additionally, pattern
matching on error_chain errors, which should be common when dealing with Lua, is
less convenient than a hand rolled error type.
So, if we decide not to use error_chain, we now have a new set of problems if we
decide interoperability with error_chain is important. The first problem we run
into is that there are two natural bounds for wrapped errors that we would
pick, (Error + Send + Sync), or just Error, and neither of them will
interoperate well with error_chain. (Error + Send + Sync) means we can't wrap
error chain errors into LuaError::ExternalError (they're missing the Sync
bound), and having the bounds be just Error means the opposite, that we can't
hold a LuaError inside an error_chain error.
We could just decide that interoperability with error_chain is the most
important qualification, and pick (Error + Send), but this causes a DIFFERENT
set of problems. The rust ecosystem has the two primary error bounds as Error
or (Error + Send + Sync), and there are Into impls from &str / String to
Box<Error + Send + Sync> for example, but NOT (Error + Send). This means that
we are forced to manually recreate the conversions from &str / String to
LuaError rather than relying on a single Into<Box<Error + Send + Sync>> bound,
but this means that string conversions have a different set of methods than
other error types for external error conversion. I have not been able to figure
out an API that I am happy with that uses the (Error + Send) bound. Box<Error>
is obnoxious because not having errors implement Send causes needless problems
in a multithreaded context, so that leaves (Error + Send + Sync). This is
actually a completely reasonable bound for external errors, and has the nice
String Into impls that we would want, the ONLY problem is that it is a pain to
interoperate with the current version of error_chain.
It would be nice to be able to specify the traits that an error generated by the
error_chain macro would implement, and this is apparently in progress in the
error_chain library. This would solve both the problem with not being able to
implement Clone and the problems with (Error + Send) bounds. I am not convinced
that this library should go back to using error_chain when that functionality is
in stable error_chain though, because of the other minor usability problems with
using error_chain.
In that theoretical situation, the downside of NOT using error_chain is simply
that there would not be automatic stacktraces of LuaError. This is not a huge
problem, because stack traces of lua errors are not extremely useful, and for
external errors it is not too hard to create a different version of the
LuaExternalResult / LuaExternalError traits and do conversion from an
error_chain type into a type that will print the stacktrace on display, or
use downcasting in the error causes.
So in summary, this library is no longer using error_chain, and probably will
not use it again in the future. Currently this means that to interoperate with
error_chain, you should use error_chain 0.8.1, which derives Sync on errors, or
wait for a version that supports user defined trait derives. In the future
when error_chain supports user defined trait derives, users may have to take an
extra step to make wrapped external errors print the stacktrace that they
capture.
This change works, but is not entirely complete. There is no error
documentation yet, and the change brought to a head an ugly module organization
problem. There will be more commits for documentation and reorganization, then
a new stable version of rlua.
2017-06-24 18:11:56 -04:00
|
|
|
)?)
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
}).ok_or(LuaError::UserDataTypeMismatch)?
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
fn inspect<'a, T, R, F>(&'a self, func: F) -> Option<R>
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
|
|
|
T: LuaUserDataType,
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
F: FnOnce(&'a RefCell<T>) -> R,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
|
|
|
unsafe {
|
|
|
|
let lua = self.0.lua;
|
|
|
|
stack_guard(lua.state, 0, move || {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(lua.state, 3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-05-25 00:43:35 -04:00
|
|
|
lua.push_ref(lua.state, &self.0);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
lua_assert!(
|
|
|
|
lua.state,
|
2017-06-25 04:25:48 -04:00
|
|
|
ffi::lua_getmetatable(lua.state, -1) != 0,
|
|
|
|
"LuaUserData missing metatable"
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-15 10:26:39 -04:00
|
|
|
ffi::lua_rawgeti(
|
|
|
|
lua.state,
|
|
|
|
ffi::LUA_REGISTRYINDEX,
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
lua.userdata_metatable::<T>() as ffi::lua_Integer,
|
2017-06-15 10:26:39 -04:00
|
|
|
);
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
|
2017-05-21 19:50:59 -04:00
|
|
|
if ffi::lua_rawequal(lua.state, -1, -2) == 0 {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
ffi::lua_pop(lua.state, 3);
|
|
|
|
None
|
|
|
|
} else {
|
2017-07-23 01:00:33 -04:00
|
|
|
let res = func(&*get_userdata::<RefCell<T>>(lua.state, -3));
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
ffi::lua_pop(lua.state, 3);
|
|
|
|
Some(res)
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Top level Lua struct which holds the Lua state itself.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub struct Lua {
|
|
|
|
state: *mut ffi::lua_State,
|
2017-06-05 05:03:18 -04:00
|
|
|
main_state: *mut ffi::lua_State,
|
2017-05-21 19:50:59 -04:00
|
|
|
ephemeral: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Lua {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
if !self.ephemeral {
|
2017-06-05 05:03:18 -04:00
|
|
|
ffi::lua_close(self.state);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Lua {
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Creates a new Lua state.
|
|
|
|
///
|
|
|
|
/// Also loads the standard library.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn new() -> Lua {
|
|
|
|
unsafe {
|
|
|
|
let state = ffi::luaL_newstate();
|
|
|
|
|
|
|
|
stack_guard(state, 0, || {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
ffi::luaL_openlibs(state);
|
|
|
|
|
|
|
|
// Create the userdata registry table
|
|
|
|
|
2017-06-15 10:26:39 -04:00
|
|
|
ffi::lua_pushlightuserdata(
|
|
|
|
state,
|
|
|
|
&LUA_USERDATA_REGISTRY_KEY as *const u8 as *mut c_void,
|
|
|
|
);
|
|
|
|
|
2017-07-23 01:00:33 -04:00
|
|
|
push_userdata::<RefCell<HashMap<TypeId, c_int>>>(state, RefCell::new(HashMap::new()));
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
ffi::lua_newtable(state);
|
|
|
|
|
|
|
|
push_string(state, "__gc");
|
2017-07-23 01:00:33 -04:00
|
|
|
ffi::lua_pushcfunction(state, userdata_destructor::<RefCell<HashMap<TypeId, c_int>>>);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
ffi::lua_setmetatable(state, -2);
|
|
|
|
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
// Create the function metatable
|
|
|
|
|
2017-06-15 10:26:39 -04:00
|
|
|
ffi::lua_pushlightuserdata(
|
|
|
|
state,
|
|
|
|
&FUNCTION_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void,
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
ffi::lua_newtable(state);
|
|
|
|
|
|
|
|
push_string(state, "__gc");
|
2017-07-23 01:00:33 -04:00
|
|
|
ffi::lua_pushcfunction(state, userdata_destructor::<LuaCallback>);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
push_string(state, "__metatable");
|
|
|
|
ffi::lua_pushboolean(state, 0);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
// Override pcall / xpcall
|
|
|
|
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_rawgeti(state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
|
|
|
|
|
|
|
|
push_string(state, "pcall");
|
|
|
|
ffi::lua_pushcfunction(state, safe_pcall);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
push_string(state, "xpcall");
|
|
|
|
ffi::lua_pushcfunction(state, safe_xpcall);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
ffi::lua_pop(state, 1);
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
});
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
Lua {
|
|
|
|
state,
|
2017-06-05 05:03:18 -04:00
|
|
|
main_state: state,
|
2017-05-21 19:50:59 -04:00
|
|
|
ephemeral: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-21 20:38:58 -04:00
|
|
|
/// Loads a chunk of Lua code and returns it as a function.
|
2017-06-17 21:23:17 -04:00
|
|
|
///
|
2017-06-27 14:05:49 -04:00
|
|
|
/// The source can be named by setting the `name` parameter. This is generally recommended as it
|
|
|
|
/// results in better error traces.
|
2017-06-17 21:23:17 -04:00
|
|
|
///
|
2017-06-21 20:38:58 -04:00
|
|
|
/// Equivalent to Lua's `load` function.
|
|
|
|
pub fn load(&self, source: &str, name: Option<&str>) -> LuaResult<LuaFunction> {
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
stack_err_guard(self.state, 0, || {
|
2017-06-15 10:26:39 -04:00
|
|
|
handle_error(
|
|
|
|
self.state,
|
|
|
|
if let Some(name) = name {
|
2017-06-24 20:57:04 -04:00
|
|
|
let name = CString::new(name.to_owned()).map_err(|e| {
|
2017-06-25 04:25:48 -04:00
|
|
|
LuaError::ToLuaConversionError(e.to_string())
|
2017-06-24 20:57:04 -04:00
|
|
|
})?;
|
2017-06-15 10:26:39 -04:00
|
|
|
ffi::luaL_loadbuffer(
|
|
|
|
self.state,
|
|
|
|
source.as_ptr() as *const c_char,
|
|
|
|
source.len(),
|
|
|
|
name.as_ptr(),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
ffi::luaL_loadbuffer(
|
|
|
|
self.state,
|
|
|
|
source.as_ptr() as *const c_char,
|
|
|
|
source.len(),
|
|
|
|
ptr::null(),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
)?;
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-21 20:38:58 -04:00
|
|
|
Ok(LuaFunction(self.pop_ref(self.state)))
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-21 20:38:58 -04:00
|
|
|
/// Execute a chunk of Lua code.
|
|
|
|
///
|
2017-06-27 14:05:49 -04:00
|
|
|
/// This is equivalent to simply loading the source with `load` and then calling the resulting
|
|
|
|
/// function with no arguments.
|
2017-06-21 20:38:58 -04:00
|
|
|
///
|
|
|
|
/// Returns the values returned by the chunk.
|
|
|
|
pub fn exec<'lua, R: FromLuaMulti<'lua>>(
|
|
|
|
&'lua self,
|
|
|
|
source: &str,
|
|
|
|
name: Option<&str>,
|
|
|
|
) -> LuaResult<R> {
|
|
|
|
self.load(source, name)?.call(())
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Evaluate the given expression or chunk inside this Lua state.
|
|
|
|
///
|
2017-06-27 14:05:49 -04:00
|
|
|
/// If `source` is an expression, returns the value it evaluates to. Otherwise, returns the
|
|
|
|
/// values returned by the chunk (if any).
|
2017-07-16 16:53:32 -04:00
|
|
|
pub fn eval<'lua, R: FromLuaMulti<'lua>>(
|
|
|
|
&'lua self,
|
|
|
|
source: &str,
|
2017-07-19 20:10:11 -04:00
|
|
|
name: Option<&str>,
|
2017-07-16 16:53:32 -04:00
|
|
|
) -> LuaResult<R> {
|
2017-07-19 20:10:11 -04:00
|
|
|
// First, try interpreting the lua as an expression by adding
|
|
|
|
// "return", then as a statement. This is the same thing the
|
|
|
|
// actual lua repl does.
|
2017-07-16 16:53:32 -04:00
|
|
|
self.load(&format!("return {}", source), name)
|
|
|
|
.or_else(|_| self.load(source, name))?
|
|
|
|
.call(())
|
2017-06-21 18:13:49 -04:00
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Pass a `&str` slice to Lua, creating and returning a interned Lua string.
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
pub fn create_string(&self, s: &str) -> LuaString {
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe {
|
|
|
|
stack_guard(self.state, 0, || {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(self.state, 1);
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_pushlstring(self.state, s.as_ptr() as *const c_char, s.len());
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
LuaString(self.pop_ref(self.state))
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Creates and returns a new table.
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
pub fn create_table(&self) -> LuaTable {
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe {
|
|
|
|
stack_guard(self.state, 0, || {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(self.state, 1);
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_newtable(self.state);
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
LuaTable(self.pop_ref(self.state))
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Creates a table and fills it with values from an iterator.
|
2017-07-19 21:28:16 -04:00
|
|
|
pub fn create_table_from<'lua, K, V, I>(&'lua self, cont: I) -> LuaResult<LuaTable<'lua>>
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
|
|
|
K: ToLua<'lua>,
|
|
|
|
V: ToLua<'lua>,
|
|
|
|
I: IntoIterator<Item = (K, V)>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
2017-06-05 01:46:45 -04:00
|
|
|
unsafe {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
stack_err_guard(self.state, 0, || {
|
|
|
|
check_stack(self.state, 3);
|
2017-06-05 01:46:45 -04:00
|
|
|
ffi::lua_newtable(self.state);
|
|
|
|
|
2017-06-15 16:27:39 -04:00
|
|
|
for (k, v) in cont {
|
2017-06-19 02:57:03 -04:00
|
|
|
self.push_value(self.state, k.to_lua(self)?);
|
|
|
|
self.push_value(self.state, v.to_lua(self)?);
|
2017-06-05 01:46:45 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
|
|
|
}
|
|
|
|
Ok(LuaTable(self.pop_ref(self.state)))
|
|
|
|
})
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Creates a table from an iterator of values, using `1..` as the keys.
|
2017-07-19 21:28:16 -04:00
|
|
|
pub fn create_sequence_from<'lua, T, I>(&'lua self, cont: I) -> LuaResult<LuaTable<'lua>>
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
|
|
|
T: ToLua<'lua>,
|
|
|
|
I: IntoIterator<Item = T>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
2017-06-20 19:04:25 -04:00
|
|
|
self.create_table_from(cont.into_iter().enumerate().map(|(k, v)| (k + 1, v)))
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Wraps a Rust function or closure, creating a callable Lua function handle to it.
|
2017-07-19 21:28:16 -04:00
|
|
|
pub fn create_function<'lua, F>(&'lua self, func: F) -> LuaFunction<'lua>
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
2017-07-19 21:28:16 -04:00
|
|
|
F: 'lua + for<'a> FnMut(&'a Lua, LuaMultiValue<'a>) -> LuaResult<LuaMultiValue<'a>>,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
|
|
|
self.create_callback_function(Box::new(func))
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Wraps a Lua function into a new thread (or coroutine).
|
|
|
|
///
|
|
|
|
/// Equivalent to `coroutine.create`.
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
pub fn create_thread<'lua>(&'lua self, func: LuaFunction<'lua>) -> LuaThread<'lua> {
|
2017-05-24 23:13:58 -04:00
|
|
|
unsafe {
|
|
|
|
stack_guard(self.state, 0, move || {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(self.state, 1);
|
2017-05-24 23:13:58 -04:00
|
|
|
|
|
|
|
let thread_state = ffi::lua_newthread(self.state);
|
2017-05-25 00:43:35 -04:00
|
|
|
self.push_ref(thread_state, &func.0);
|
|
|
|
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
LuaThread(self.pop_ref(self.state))
|
2017-05-24 23:13:58 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Create a Lua userdata object from a custom userdata type.
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
pub fn create_userdata<T>(&self, data: T) -> LuaUserData
|
2017-06-15 10:26:39 -04:00
|
|
|
where
|
|
|
|
T: LuaUserDataType,
|
2017-05-21 19:50:59 -04:00
|
|
|
{
|
|
|
|
unsafe {
|
|
|
|
stack_guard(self.state, 0, move || {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(self.state, 2);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-07-23 01:00:33 -04:00
|
|
|
push_userdata::<RefCell<T>>(self.state, RefCell::new(data));
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-15 10:26:39 -04:00
|
|
|
ffi::lua_rawgeti(
|
|
|
|
self.state,
|
|
|
|
ffi::LUA_REGISTRYINDEX,
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
self.userdata_metatable::<T>() as ffi::lua_Integer,
|
2017-06-15 10:26:39 -04:00
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
ffi::lua_setmetatable(self.state, -2);
|
|
|
|
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
LuaUserData(self.pop_ref(self.state))
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Returns a handle to the global environment.
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
pub fn globals(&self) -> LuaTable {
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
stack_guard(self.state, 0, move || {
|
|
|
|
check_stack(self.state, 1);
|
|
|
|
ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
|
|
|
|
LuaTable(self.pop_ref(self.state))
|
|
|
|
})
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Coerces a Lua value to a string.
|
|
|
|
///
|
|
|
|
/// The value must be a string (in which case this is a no-op) or a number.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn coerce_string<'lua>(&'lua self, v: LuaValue<'lua>) -> LuaResult<LuaString<'lua>> {
|
|
|
|
match v {
|
|
|
|
LuaValue::String(s) => Ok(s),
|
|
|
|
v => unsafe {
|
|
|
|
stack_guard(self.state, 0, || {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(self.state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
self.push_value(self.state, v);
|
2017-05-21 19:50:59 -04:00
|
|
|
if ffi::lua_tostring(self.state, -1).is_null() {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
ffi::lua_pop(self.state, 1);
|
2017-06-25 04:25:48 -04:00
|
|
|
Err(LuaError::FromLuaConversionError(
|
|
|
|
"cannot convert lua value to string".to_owned(),
|
|
|
|
))
|
2017-05-21 19:50:59 -04:00
|
|
|
} else {
|
2017-05-25 00:43:35 -04:00
|
|
|
Ok(LuaString(self.pop_ref(self.state)))
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Coerces a Lua value to an integer.
|
|
|
|
///
|
|
|
|
/// The value must be an integer, or a floating point number or a string that can be converted
|
|
|
|
/// to an integer. Refer to the Lua manual for details.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn coerce_integer(&self, v: LuaValue) -> LuaResult<LuaInteger> {
|
|
|
|
match v {
|
|
|
|
LuaValue::Integer(i) => Ok(i),
|
|
|
|
v => unsafe {
|
|
|
|
stack_guard(self.state, 0, || {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(self.state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
self.push_value(self.state, v);
|
2017-05-21 19:50:59 -04:00
|
|
|
let mut isint = 0;
|
|
|
|
let i = ffi::lua_tointegerx(self.state, -1, &mut isint);
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
ffi::lua_pop(self.state, 1);
|
2017-05-21 19:50:59 -04:00
|
|
|
if isint == 0 {
|
2017-06-25 04:25:48 -04:00
|
|
|
Err(LuaError::FromLuaConversionError(
|
|
|
|
"cannot convert lua value to integer".to_owned(),
|
|
|
|
))
|
2017-05-21 19:50:59 -04:00
|
|
|
} else {
|
|
|
|
Ok(i)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Coerce a Lua value to a number.
|
|
|
|
///
|
|
|
|
/// The value must be a number or a string that can be converted to a number. Refer to the Lua
|
|
|
|
/// manual for details.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn coerce_number(&self, v: LuaValue) -> LuaResult<LuaNumber> {
|
|
|
|
match v {
|
|
|
|
LuaValue::Number(n) => Ok(n),
|
|
|
|
v => unsafe {
|
|
|
|
stack_guard(self.state, 0, || {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(self.state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
self.push_value(self.state, v);
|
2017-05-21 19:50:59 -04:00
|
|
|
let mut isnum = 0;
|
|
|
|
let n = ffi::lua_tonumberx(self.state, -1, &mut isnum);
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
ffi::lua_pop(self.state, 1);
|
2017-05-21 19:50:59 -04:00
|
|
|
if isnum == 0 {
|
2017-06-25 04:25:48 -04:00
|
|
|
Err(LuaError::FromLuaConversionError(
|
|
|
|
"cannot convert lua value to number".to_owned(),
|
|
|
|
))
|
2017-05-21 19:50:59 -04:00
|
|
|
} else {
|
|
|
|
Ok(n)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-25 00:47:48 -04:00
|
|
|
pub fn from<'lua, T: ToLua<'lua>>(&'lua self, t: T) -> LuaResult<LuaValue<'lua>> {
|
2017-05-21 19:50:59 -04:00
|
|
|
t.to_lua(self)
|
|
|
|
}
|
|
|
|
|
2017-05-25 00:47:48 -04:00
|
|
|
pub fn to<'lua, T: FromLua<'lua>>(&'lua self, value: LuaValue<'lua>) -> LuaResult<T> {
|
2017-05-21 19:50:59 -04:00
|
|
|
T::from_lua(value, self)
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Packs up a value that implements `ToLuaMulti` into a `LuaMultiValue` instance.
|
|
|
|
///
|
|
|
|
/// This can be used to return arbitrary Lua values from a Rust function back to Lua.
|
2017-05-21 19:50:59 -04:00
|
|
|
pub fn pack<'lua, T: ToLuaMulti<'lua>>(&'lua self, t: T) -> LuaResult<LuaMultiValue<'lua>> {
|
|
|
|
t.to_lua_multi(self)
|
|
|
|
}
|
|
|
|
|
2017-06-17 21:23:17 -04:00
|
|
|
/// Unpacks a `LuaMultiValue` instance into a value that implements `FromLuaMulti`.
|
|
|
|
///
|
|
|
|
/// This can be used to convert the arguments of a Rust function called by Lua.
|
2017-06-15 10:26:39 -04:00
|
|
|
pub fn unpack<'lua, T: FromLuaMulti<'lua>>(
|
|
|
|
&'lua self,
|
|
|
|
value: LuaMultiValue<'lua>,
|
|
|
|
) -> LuaResult<T> {
|
2017-05-21 19:50:59 -04:00
|
|
|
T::from_lua_multi(value, self)
|
|
|
|
}
|
|
|
|
|
2017-07-19 21:28:16 -04:00
|
|
|
fn create_callback_function<'lua>(&'lua self, func: LuaCallback<'lua>) -> LuaFunction<'lua> {
|
2017-05-21 19:50:59 -04:00
|
|
|
unsafe extern "C" fn callback_call_impl(state: *mut ffi::lua_State) -> c_int {
|
|
|
|
callback_error(state, || {
|
|
|
|
let lua = Lua {
|
|
|
|
state: state,
|
2017-06-05 05:03:18 -04:00
|
|
|
main_state: main_state(state),
|
2017-05-21 19:50:59 -04:00
|
|
|
ephemeral: true,
|
|
|
|
};
|
|
|
|
|
2017-07-23 01:00:33 -04:00
|
|
|
let func = &mut *get_userdata::<LuaCallback>(state, ffi::lua_upvalueindex(1));
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
let nargs = ffi::lua_gettop(state);
|
|
|
|
let mut args = LuaMultiValue::new();
|
|
|
|
for _ in 0..nargs {
|
2017-06-19 02:57:03 -04:00
|
|
|
args.push_front(lua.pop_value(state));
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
let results = func(&lua, args)?;
|
|
|
|
let nresults = results.len() as c_int;
|
|
|
|
|
|
|
|
for r in results {
|
2017-06-19 02:57:03 -04:00
|
|
|
lua.push_value(state, r);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(nresults)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
stack_guard(self.state, 0, move || {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(self.state, 2);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-07-23 01:00:33 -04:00
|
|
|
push_userdata::<LuaCallback>(self.state, func);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-15 10:26:39 -04:00
|
|
|
ffi::lua_pushlightuserdata(
|
|
|
|
self.state,
|
|
|
|
&FUNCTION_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void,
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_gettable(self.state, ffi::LUA_REGISTRYINDEX);
|
|
|
|
ffi::lua_setmetatable(self.state, -2);
|
|
|
|
|
|
|
|
ffi::lua_pushcclosure(self.state, callback_call_impl, 1);
|
|
|
|
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
LuaFunction(self.pop_ref(self.state))
|
2017-05-21 19:50:59 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
unsafe fn push_value(&self, state: *mut ffi::lua_State, value: LuaValue) {
|
|
|
|
match value {
|
|
|
|
LuaValue::Nil => {
|
|
|
|
ffi::lua_pushnil(state);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::Boolean(b) => {
|
|
|
|
ffi::lua_pushboolean(state, if b { 1 } else { 0 });
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::LightUserData(ud) => {
|
|
|
|
ffi::lua_pushlightuserdata(state, ud.0);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::Integer(i) => {
|
|
|
|
ffi::lua_pushinteger(state, i);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::Number(n) => {
|
|
|
|
ffi::lua_pushnumber(state, n);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::String(s) => {
|
|
|
|
self.push_ref(state, &s.0);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::Table(t) => {
|
|
|
|
self.push_ref(state, &t.0);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::Function(f) => {
|
|
|
|
self.push_ref(state, &f.0);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-25 01:47:55 -04:00
|
|
|
LuaValue::Thread(t) => {
|
|
|
|
self.push_ref(state, &t.0);
|
|
|
|
}
|
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaValue::UserData(ud) => {
|
|
|
|
self.push_ref(state, &ud.0);
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-25 01:47:55 -04:00
|
|
|
LuaValue::Error(e) => {
|
2017-06-25 02:04:14 -04:00
|
|
|
push_wrapped_error(state, e);
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
unsafe fn pop_value(&self, state: *mut ffi::lua_State) -> LuaValue {
|
|
|
|
match ffi::lua_type(state, -1) {
|
2017-05-25 00:43:35 -04:00
|
|
|
ffi::LUA_TNIL => {
|
|
|
|
ffi::lua_pop(state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
LuaNil
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ffi::LUA_TBOOLEAN => {
|
|
|
|
let b = LuaValue::Boolean(ffi::lua_toboolean(state, -1) != 0);
|
|
|
|
ffi::lua_pop(state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
b
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ffi::LUA_TLIGHTUSERDATA => {
|
2017-07-19 20:15:46 -04:00
|
|
|
let ud = LuaValue::LightUserData(LuaLightUserData(ffi::lua_touserdata(state, -1)));
|
2017-05-25 00:43:35 -04:00
|
|
|
ffi::lua_pop(state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
ud
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ffi::LUA_TNUMBER => {
|
|
|
|
if ffi::lua_isinteger(state, -1) != 0 {
|
|
|
|
let i = LuaValue::Integer(ffi::lua_tointeger(state, -1));
|
|
|
|
ffi::lua_pop(state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
i
|
2017-05-25 00:43:35 -04:00
|
|
|
} else {
|
|
|
|
let n = LuaValue::Number(ffi::lua_tonumber(state, -1));
|
|
|
|
ffi::lua_pop(state, 1);
|
2017-06-19 02:57:03 -04:00
|
|
|
n
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
ffi::LUA_TSTRING => LuaValue::String(LuaString(self.pop_ref(state))),
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
ffi::LUA_TTABLE => LuaValue::Table(LuaTable(self.pop_ref(state))),
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
ffi::LUA_TFUNCTION => LuaValue::Function(LuaFunction(self.pop_ref(state))),
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-25 01:47:55 -04:00
|
|
|
ffi::LUA_TUSERDATA => {
|
|
|
|
// It should not be possible to interact with userdata types
|
|
|
|
// other than custom LuaUserDataType types OR a WrappedError.
|
|
|
|
// WrappedPanic should never be able to be caught in lua, so it
|
|
|
|
// should never be here.
|
2017-06-25 02:04:14 -04:00
|
|
|
if let Some(err) = pop_wrapped_error(state) {
|
|
|
|
LuaValue::Error(err)
|
2017-06-25 01:47:55 -04:00
|
|
|
} else {
|
|
|
|
LuaValue::UserData(LuaUserData(self.pop_ref(state)))
|
|
|
|
}
|
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
|
2017-06-19 02:57:03 -04:00
|
|
|
ffi::LUA_TTHREAD => LuaValue::Thread(LuaThread(self.pop_ref(state))),
|
2017-05-25 00:43:35 -04:00
|
|
|
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
_ => unreachable!("internal error: LUA_TNONE in pop_value"),
|
2017-06-19 02:57:03 -04:00
|
|
|
}
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn push_ref(&self, state: *mut ffi::lua_State, lref: &LuaRef) {
|
2017-06-15 10:26:39 -04:00
|
|
|
assert_eq!(
|
|
|
|
lref.lua.main_state,
|
|
|
|
self.main_state,
|
|
|
|
"Lua instance passed LuaValue created from a different Lua"
|
|
|
|
);
|
|
|
|
|
|
|
|
ffi::lua_rawgeti(
|
|
|
|
state,
|
|
|
|
ffi::LUA_REGISTRYINDEX,
|
|
|
|
lref.registry_id as ffi::lua_Integer,
|
|
|
|
);
|
2017-05-25 00:43:35 -04:00
|
|
|
}
|
|
|
|
|
2017-06-18 00:28:46 -04:00
|
|
|
// Pops the topmost element of the stack and stores a reference to it in the
|
|
|
|
// registry.
|
|
|
|
//
|
|
|
|
// This pins the object, preventing garbage collection until the returned
|
|
|
|
// `LuaRef` is dropped.
|
2017-05-25 00:43:35 -04:00
|
|
|
unsafe fn pop_ref(&self, state: *mut ffi::lua_State) -> LuaRef {
|
|
|
|
let registry_id = ffi::luaL_ref(state, ffi::LUA_REGISTRYINDEX);
|
|
|
|
LuaRef {
|
|
|
|
lua: self,
|
|
|
|
registry_id: registry_id,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
unsafe fn userdata_metatable<T: LuaUserDataType>(&self) -> c_int {
|
2017-05-21 19:50:59 -04:00
|
|
|
// Used if both an __index metamethod is set and regular methods, checks methods table
|
|
|
|
// first, then __index metamethod.
|
|
|
|
unsafe extern "C" fn meta_index_impl(state: *mut ffi::lua_State) -> c_int {
|
|
|
|
ffi::lua_pushvalue(state, -1);
|
|
|
|
ffi::lua_gettable(state, ffi::lua_upvalueindex(1));
|
|
|
|
if ffi::lua_isnil(state, -1) == 0 {
|
|
|
|
ffi::lua_insert(state, -3);
|
|
|
|
ffi::lua_pop(state, 2);
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
ffi::lua_pop(state, 1);
|
|
|
|
ffi::lua_pushvalue(state, ffi::lua_upvalueindex(2));
|
|
|
|
ffi::lua_insert(state, -3);
|
|
|
|
ffi::lua_call(state, 2, 1);
|
|
|
|
1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stack_guard(self.state, 0, move || {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
check_stack(self.state, 5);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
2017-06-15 10:26:39 -04:00
|
|
|
ffi::lua_pushlightuserdata(
|
|
|
|
self.state,
|
|
|
|
&LUA_USERDATA_REGISTRY_KEY as *const u8 as *mut c_void,
|
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_gettable(self.state, ffi::LUA_REGISTRYINDEX);
|
2017-07-23 01:00:33 -04:00
|
|
|
let registered_userdata = &mut *get_userdata::<RefCell<HashMap<TypeId, c_int>>>(self.state, -1);
|
2017-05-21 19:50:59 -04:00
|
|
|
let mut map = (*registered_userdata).borrow_mut();
|
|
|
|
ffi::lua_pop(self.state, 1);
|
|
|
|
|
|
|
|
match map.entry(TypeId::of::<T>()) {
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
HashMapEntry::Occupied(entry) => *entry.get(),
|
2017-05-21 19:50:59 -04:00
|
|
|
HashMapEntry::Vacant(entry) => {
|
|
|
|
ffi::lua_newtable(self.state);
|
|
|
|
|
|
|
|
let mut methods = LuaUserDataMethods {
|
|
|
|
methods: HashMap::new(),
|
|
|
|
meta_methods: HashMap::new(),
|
|
|
|
_type: PhantomData,
|
|
|
|
};
|
|
|
|
T::add_methods(&mut methods);
|
|
|
|
|
|
|
|
let has_methods = !methods.methods.is_empty();
|
|
|
|
|
|
|
|
if has_methods {
|
|
|
|
push_string(self.state, "__index");
|
|
|
|
ffi::lua_newtable(self.state);
|
|
|
|
|
|
|
|
for (k, m) in methods.methods {
|
|
|
|
push_string(self.state, &k);
|
2017-06-15 10:26:39 -04:00
|
|
|
self.push_value(
|
|
|
|
self.state,
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
LuaValue::Function(self.create_callback_function(m)),
|
2017-06-19 02:57:03 -04:00
|
|
|
);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
for (k, m) in methods.meta_methods {
|
|
|
|
if k == LuaMetaMethod::Index && has_methods {
|
|
|
|
push_string(self.state, "__index");
|
|
|
|
ffi::lua_pushvalue(self.state, -1);
|
|
|
|
ffi::lua_gettable(self.state, -3);
|
2017-06-15 10:26:39 -04:00
|
|
|
self.push_value(
|
|
|
|
self.state,
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
LuaValue::Function(self.create_callback_function(m)),
|
2017-06-19 02:57:03 -04:00
|
|
|
);
|
2017-05-21 19:50:59 -04:00
|
|
|
ffi::lua_pushcclosure(self.state, meta_index_impl, 2);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
} else {
|
|
|
|
let name = match k {
|
|
|
|
LuaMetaMethod::Add => "__add",
|
|
|
|
LuaMetaMethod::Sub => "__sub",
|
|
|
|
LuaMetaMethod::Mul => "__mul",
|
|
|
|
LuaMetaMethod::Div => "__div",
|
|
|
|
LuaMetaMethod::Mod => "__mod",
|
|
|
|
LuaMetaMethod::Pow => "__pow",
|
|
|
|
LuaMetaMethod::Unm => "__unm",
|
2017-06-18 00:28:46 -04:00
|
|
|
LuaMetaMethod::IDiv => "__idiv",
|
|
|
|
LuaMetaMethod::BAnd => "__band",
|
|
|
|
LuaMetaMethod::BOr => "__bor",
|
|
|
|
LuaMetaMethod::BXor => "__bxor",
|
|
|
|
LuaMetaMethod::BNot => "__bnot",
|
|
|
|
LuaMetaMethod::Shl => "__shl",
|
|
|
|
LuaMetaMethod::Shr => "__shr",
|
2017-05-21 19:50:59 -04:00
|
|
|
LuaMetaMethod::Concat => "__concat",
|
|
|
|
LuaMetaMethod::Len => "__len",
|
|
|
|
LuaMetaMethod::Eq => "__eq",
|
|
|
|
LuaMetaMethod::Lt => "__lt",
|
|
|
|
LuaMetaMethod::Le => "__le",
|
|
|
|
LuaMetaMethod::Index => "__index",
|
|
|
|
LuaMetaMethod::NewIndex => "__newIndex",
|
|
|
|
LuaMetaMethod::Call => "__call",
|
2017-06-23 15:24:03 -04:00
|
|
|
LuaMetaMethod::ToString => "__tostring",
|
2017-05-21 19:50:59 -04:00
|
|
|
};
|
|
|
|
push_string(self.state, name);
|
2017-06-15 10:26:39 -04:00
|
|
|
self.push_value(
|
|
|
|
self.state,
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
LuaValue::Function(self.create_callback_function(m)),
|
2017-06-19 02:57:03 -04:00
|
|
|
);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
push_string(self.state, "__gc");
|
2017-07-23 01:00:33 -04:00
|
|
|
ffi::lua_pushcfunction(self.state, userdata_destructor::<RefCell<T>>);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
push_string(self.state, "__metatable");
|
|
|
|
ffi::lua_pushboolean(self.state, 0);
|
2017-06-05 00:03:39 -04:00
|
|
|
ffi::lua_rawset(self.state, -3);
|
2017-05-21 19:50:59 -04:00
|
|
|
|
|
|
|
let id = ffi::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX);
|
|
|
|
entry.insert(id);
|
Another major API change, out of stack space is not an Err
It, ahem "should not" be possible to exhaust lua stack space in normal usage,
and causing stack errors to be Err is slightly obnoxious. I have been wanting
to make this change for a while, and removing the callback API from tables makes
this sensible *I think*.
I can think of a couple of ways that this is not technically true, but I think
that they are acceptable, or should be handled differently.
One, you can make arbitrarily sized LuaVariadic values. I think this is maybe a
bug already, because there is an argument limit in Lua which is lower than the
stack limit. I'm not sure what happens there, but if it is a stack based panic,
(or any panic?) it is a bug.
Two, I believe that if you recurse over and over between lua -> rust -> lua ->
rust etc, and call rlua API functions, you might get a stack panic. I think for
trusted lua code, this is morally equivalent to a regular stack overflow in
plain rust, which is already.. well it's not a panic but it's some kind of safe
crash I'm not sure, so I think this is acceptable. For *untrusted* lua code,
this could theoretically be a problem if the API provided a callback that would
call back into lua, then some lua script could force a stack based panic. There
are so many concerns with untrusted lua code, and this library is NOT safe
enough yet for untrusted code (it doesn't even provide an option to limit lua to
the safe API subset yet!), so this is not currently an issue. When the library
provides support for "safe lua", it should come with big warnings anyway, and
being able to force a stack panic is pretty minor in comparison.
I think if there are other ways to cause unbounded stack usage, that it is a
bug, or there can be an error just for that situation, like argument count
limits.
This commit also fixes several stupid bugs with tests, stack checking, and
panics.
2017-06-25 16:52:32 -04:00
|
|
|
id
|
2017-05-21 19:50:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static LUA_USERDATA_REGISTRY_KEY: u8 = 0;
|
|
|
|
static FUNCTION_METATABLE_REGISTRY_KEY: u8 = 0;
|