Documentation updates for new handle behavior, and some minor cleanup

This commit is contained in:
kyren 2018-03-12 17:50:48 -04:00
parent 4358034bbf
commit c6c90f201c
4 changed files with 34 additions and 32 deletions

View file

@ -6,20 +6,19 @@
[Guided Tour](examples/guided_tour.rs)
This library is a high level interface between Rust and Lua. Its major goal is
to expose as easy to use, practical, and flexible of an API between Rust and Lua
as possible, while also being completely safe.
This library is a high level interface between Rust and Lua. Its major goals
are to expose as easy to use, practical, and flexible of an API between Rust and
Lua as possible, while also being *completely* safe.
`rlua` is designed around "registry handles" to values inside the Lua state.
This means that when you get a type like `rlua::Table` or `rlua::Function` in
Rust, what you actually hold is an integer key into the Lua registry. This is
different from the bare Lua C API, where you create tables / functions on the
Lua stack and must be aware of their stack location. This is also similar to
how other Lua bindings systems like
[Selene](https://github.com/jeremyong/Selene) for C++ work, but it means that
using `rlua` may be slightly slower than what you could conceivably write using
the C API. The reasons for this design are safety and flexibility, and to
prevent the user of `rlua` from having to be aware of the Lua stack at all.
`rlua` is NOT designed to be a perfect zero cost wrapper over the Lua C API,
because such a wrapper cannot maintain the safety guarantees that `rlua` is
designed to have. Every place where the Lua C API may trigger an error longjmp
in any way is protected by `lua_pcall`, and the user of the library is protected
from directly interacting with unsafe things like the Lua stack, and there is
overhead associated with this safety. However, performance *is* a focus of the
library to the extent possible while maintaining safety, so if you encounter
something that egregiously worse than using the Lua C API directly, or simply
something you feel could perform better, feel free to file a bug report.
There are currently a few missing pieces of this API:
@ -30,8 +29,7 @@ There are currently a few missing pieces of this API:
* "Context" or "Sandboxing" support. There should be the ability to set the
`_ENV` upvalue of a loaded chunk to a table other than `_G`, so that you can
have different environments for different loaded chunks.
* Benchmarks, and quantifying performance differences with what you would
might write in C.
* Quantifying performance differences to direct use of the Lua C API.
Additionally, there are ways I would like to change this API, once support lands
in rustc. For example:
@ -40,11 +38,6 @@ in rustc. For example:
by macro for tuples up to size 12, it would be great if this was replaced
with real variadic generics when this is available in Rust.
It is also worth it to list some non-goals for the project:
* Be a perfect zero cost wrapper over the Lua C API
* Allow the user to do absolutely everything that the Lua C API might allow
## API stability
This library is very much Work In Progress, so there is a some API churn.
@ -68,11 +61,11 @@ there ARE several internal panics and even aborts in `rlua` source, but they
should not be possible to trigger, and if you trigger them this should be
considered a bug.
There are some caveats to the panic / abort guarantee, however:
Caveats to the panic / abort guarantee:
* `rlua` reserves the right to panic on API usage errors. Currently, the only
time this will happen is when passed a registry handle type from a different
main Lua state.
Lua state.
* Currently, there are no memory or execution limits on scripts, so untrusted
scripts can always at minimum infinite loop or allocate arbitrary amounts of
memory.

View file

@ -558,7 +558,7 @@ impl Lua {
/// [`create_registry_value`]: #method.create_registry_value
pub fn registry_value<'lua, T: FromLua<'lua>>(&'lua self, key: &RegistryKey) -> Result<T> {
unsafe {
if !Arc::ptr_eq(&key.unref_list, &(*self.extra()).registry_unref_list) {
if !self.owns_registry_value(key) {
return Err(Error::MismatchedRegistryKey);
}
@ -585,7 +585,7 @@ impl Lua {
/// [`expire_registry_values`]: #method.expire_registry_values
pub fn remove_registry_value(&self, key: RegistryKey) -> Result<()> {
unsafe {
if !Arc::ptr_eq(&key.unref_list, &(*self.extra()).registry_unref_list) {
if !self.owns_registry_value(&key) {
return Err(Error::MismatchedRegistryKey);
}
@ -606,8 +606,9 @@ impl Lua {
/// Remove any registry values whose `RegistryKey`s have all been dropped.
///
/// Unlike normal handle values, `RegistryKey`s cannot automatically clean up their registry
/// entries on Drop, but you can call this method to remove any unreachable registry values.
/// Unlike normal handle values, `RegistryKey`s do not automatically remove themselves on Drop,
/// but you can call this method to remove any unreachable registry values not manually removed
/// by `Lua::remove_registry_value`.
pub fn expire_registry_values(&self) {
unsafe {
let unref_list = mem::replace(

View file

@ -21,17 +21,22 @@ pub(crate) type Callback<'lua, 'a> =
/// An auto generated key into the Lua registry.
///
/// This is a handle into a value stored inside the Lua registry, similar to the normal handle types
/// like `Table` or `Function`. The difference is that this handle does not require holding a
/// reference to a parent `Lua` instance, and thus is managed differently. Though it is more
/// difficult to use than the normal handle types, it is Send + Sync + 'static, which means that it
/// can be used in many situations where it would be impossible to store a regular handle value.
/// This is a handle to a value stored inside the Lua registry. It is not directly usable like the
/// `Table` or `Function` handle types, but it is much more flexible and can be used in many
/// situations where it is impossible to directly store a normal handle type. It is Send + Sync +
/// 'static, and can be used by *any* `Lua` instance as long as it is derived from the same
/// underlying main state (such as one received in a Rust callback). It is not automatically
/// garbage collected on Drop, but it can be removed with [`Lua::remove_registry_value`], and
/// instances not manually removed can be garbage collected with [`Lua::expire_registry_values`].
///
/// Be warned, If you place this into Lua via a `UserData` type or a rust callback, it is *very
/// easy* to accidentally cause reference cycles that the Lua garbage collector cannot resolve.
/// Instead of placing a `RegistryKey` into a `UserData` type, prefer instead to use
/// `UserData::set_user_value` / `UserData::get_user_value`, and instead of moving a RegistryKey
/// into a callback, prefer `Lua::scope`.
///
/// [`Lua::remove_registry_value`]: struct.Lua.html#method.remove_registry_value
/// [`Lua::expire_registry_values`]: struct.Lua.html#method.expire_registry_values
pub struct RegistryKey {
pub(crate) registry_id: c_int,
pub(crate) unref_list: Arc<Mutex<Option<Vec<c_int>>>>,

View file

@ -10,7 +10,10 @@ use thread::Thread;
use userdata::AnyUserData;
use lua::Lua;
/// A dynamically typed Lua value.
/// A dynamically typed Lua value. The `String`, `Table`, `Function`, `Thread`, and `UserData`
/// variants contain handle types into the internal Lua state. It is a logic error to mix handle
/// types between separate `Lua` instances, or between a parent `Lua` instance and one received as a
/// parameter in a Rust callback, and doing so will result in a panic.
#[derive(Debug, Clone)]
pub enum Value<'lua> {
/// The Lua value `nil`.