Not only was this code not equivalent, it didn't even run since varargs
cannot be used as an upvalue (it's multiple values, after all).
Since Lua does not allow passing 2 sets of variadic arguments to a
function, the resulting code would be *very* complex and would involve
packing both sets of varargs into tables, concatenating them, then
`table.unpack`ing them to finally pass them.
This complex code would only make the docs more difficult to understand,
which is the opposite effect I originally intended with this. Let's just
get rid of this bad equivalence.
> Examples use ?, not try!, not unwrap (C-QUESTION-MARK)
> Like it or not, example code is often copied verbatim by users.
> Unwrapping an error should be a conscious decision that the user
> needs to make.
Rename the following:
LuaNil => Nil
LuaExternalError => ExternalError
LuaExternalResult => ExternalResult
LuaCallback => Callback (internal only)
Use qualified re-exports at the top of the module.
Add a new public 'prelude' module which re-exports everything with a
non-conflicting name (Adds back the Lua prefix), and is meant to be imported
unqualified.
This required a lot of little adjustments where we used std's `String`
before. In downstream code, this shouldn't be necessary, as you can just
do `use rlua::String as LuaString` to disambiguate.
Lua 5.3 has the ability for scripts to define __gc metamethods on
tables, which gives them the ability to "resurrect" userdata after __gc
has been called. This means, __gc can be called multiple times on
userdata. This commit protects against this by simply panicking on
access after resurrection. This is possibly not the best approach?
I know, this is the opposite of PR #17 wishes to do, please don't take this as
an indication that I would wish to do the opposite. I actually want to discuss
PR #17 with you, but I'm not sure about it yet, and my pedantry will not allow
me to let this remain inconsistent in the meantime. This way, either way it's
consistent haha.
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.
I'm not 100% sold on the LuaError design, I think there are a lot of questions
still, but there have been enough bugfixes that it's better to do a cargo bump.
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.
Lua should be consistent independent of the way they are produced. pcall in lua
should produce the same sort of error that would be returned by a LuaError
conversion.
The situation is not currently great, because LuaError is not Clone, so passing
a LuaError back into rust will result in the error being "consumed".
There is no single obvious form for a set in lua, and it is not very difficult
to accept a table and convert the sequence values into a set.
Also rename some methods as per discussion.
When talking about "loading" Lua code, it usually means compiling a
chunk of code into a runnable Lua function, but without actually
running it. This makes that clear.
For this to work, both `T` and `E` need to implement `ToLua`. An `Ok(t)`
passes the contained `T`, while an `Err(e)` passes `nil` followed by the
contained `E`. This matches the common Lua idiom used by functions like
`io.open`.
Closes#3
partially for the selfish reason that my submodule setup does not deal well with
ureleased versions of cargo libs where the version number ends with -pre
Allow load to return values, allows reimplementing require() like functions
properly.
Make globals table explicit in Lua, remove Lua::get / Lua::set in favor of
Lua::globals. Allows obeying globals metatable, using other Table functions on
the globals table.
Also added "has" method as shorthand for checking whether a table entry is not
nil.
There should be drastically less ways to cause unprotected lua errors now, as
the LuaTable functions which were trivial to cause unprotected errors are now
protected. Unfortunately, they are protected in a pretty slow, terrible way
right now, but it at least works.
Also, set the atpanic function in lua to call a proper rust panic instead.