From c6c90f201c67be96a6be76c7f302ba2f2a5d8d15 Mon Sep 17 00:00:00 2001 From: kyren Date: Mon, 12 Mar 2018 17:50:48 -0400 Subject: [PATCH] Documentation updates for new handle behavior, and some minor cleanup --- README.md | 37 +++++++++++++++---------------------- src/lua.rs | 9 +++++---- src/types.rs | 15 ++++++++++----- src/value.rs | 5 ++++- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 496328f..67423a7 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/src/lua.rs b/src/lua.rs index c858ef3..c021532 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -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 { 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( diff --git a/src/types.rs b/src/types.rs index 48fe6c0..cf6961d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -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>>>, diff --git a/src/value.rs b/src/value.rs index d8eb033..690a0a0 100644 --- a/src/value.rs +++ b/src/value.rs @@ -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`.