From ad6cf21921055eac5746db6438b58b8ae3961bc5 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 28 Jul 2017 12:50:30 +0200 Subject: [PATCH 1/2] Document `Error` I didn't yet document *everything* there is to say (in particular, how exactly custom Rust errors can be passed through Lua), but I've some changes to this type in mind that I'll do next. --- src/error.rs | 65 ++++++++++++++++++++++++++++++++++++++++++++-------- src/lua.rs | 27 +++++++++++++++------- 2 files changed, 74 insertions(+), 18 deletions(-) diff --git a/src/error.rs b/src/error.rs index 6904dcc..2fcb838 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use std::error::Error as StdError; use std::result::Result as StdResult; +/// Error type returned by rlua methods. #[derive(Debug, Clone)] pub enum Error { /// Lua syntax error, aka `LUA_ERRSYNTAX` that is NOT an incomplete statement. @@ -10,29 +11,73 @@ pub enum Error { /// Lua syntax error that IS an incomplete statement. Useful for implementing a REPL. IncompleteStatement(String), /// Lua runtime error, aka `LUA_ERRRUN`. + /// + /// The Lua VM returns this error when a builtin operation is performed on incompatible typed. + /// Among other things, this includes invoking operators on wrong types (such as calling or + /// indexing a `nil` value). RuntimeError(String), /// Lua error from inside an error handler, aka `LUA_ERRERR`. + /// + /// To prevent an infinite recursion when invoking an error handler, this error will be returned + /// instead of invoking the error handler. ErrorError(String), - /// A generic Rust -> Lua conversion error. + /// A Rust value could not be converted to a Lua value. ToLuaConversionError(String), - /// A generic Lua -> Rust conversion error. + /// A Lua value could not be converted to the expected Rust type. FromLuaConversionError(String), - /// A `Thread` was resumed and the coroutine was no longer active. + /// [`Thread::resume`] was called on an inactive coroutine. + /// + /// A coroutine is inactive if its main function has returned or if an error has occured inside + /// the coroutine. + /// + /// [`Thread::status`] can be used to check if the coroutine can be resumed without causing this + /// error. + /// + /// [`Thread::resume`]: struct.Thread.html#method.resume + /// [`Thread::status`]: struct.Thread.html#method.status CoroutineInactive, - /// An `AnyUserData` is not the expected type in a borrow. + /// An [`AnyUserData`] is not the expected type in a borrow. + /// + /// This error can only happen when manually using [`AnyUserData`], or when implementing + /// metamethods for binary operators. Refer to the documentation of [`UserDataMethods`] for + /// details. + /// + /// [`AnyUserData`]: struct.AnyUserData.html + /// [`UserDataMethods`]: struct.UserDataMethods.html UserDataTypeMismatch, - /// An `AnyUserData` immutable borrow failed because it is already borrowed mutably. + /// An [`AnyUserData`] immutable borrow failed because it is already borrowed mutably. + /// + /// This error can occur when a method on a [`UserData`] type calls back into Lua, which then + /// tries to call a method on the same [`UserData`] type. Consider restructuring your API to + /// prevent these errors. + /// + /// [`AnyUserData`]: struct.AnyUserData.html + /// [`UserData`]: trait.UserData.html UserDataBorrowError, - /// An `AnyUserData` mutable borrow failed because it is already borrowed. + /// An [`AnyUserData`] mutable borrow failed because it is already borrowed. + /// + /// This error can occur when a method on a [`UserData`] type calls back into Lua, which then + /// tries to call a method on the same [`UserData`] type. Consider restructuring your API to + /// prevent these errors. + /// + /// [`AnyUserData`]: struct.AnyUserData.html + /// [`UserData`]: trait.UserData.html UserDataBorrowMutError, - /// Lua error that originated as a Error in a callback. The first field is the lua error as - /// a string, the second field is the Arc holding the original Error. + /// A Rust callback returned `Err`, raising the contained `Error` as a Lua error. + /// + /// The first field is the Lua traceback, the second field holds the original error. CallbackError(String, Arc), - /// Any custom external error type, mostly useful for returning external error types from - /// callbacks. + /// A custom error. + /// + /// This can be used for returning user-defined errors from callbacks. + /// + /// Returning `Err(ExternalError(...))` from a Rust callback will raise the error as a Lua + /// error. The Rust code that originally invoked the Lua code then receives a `CallbackError`, + /// from which the original error (and a stack traceback) can be recovered. ExternalError(Arc), } +/// A specialized `Result` type used by rlua's API. pub type Result = StdResult; impl fmt::Display for Error { diff --git a/src/lua.rs b/src/lua.rs index 3c98376..692d16d 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -766,16 +766,18 @@ impl<'lua> Function<'lua> { } /// Status of a Lua thread (or coroutine). -/// -/// A `Thread` is `Active` before the coroutine function finishes, Dead after it finishes, and in -/// Error state if error has been called inside the coroutine. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum ThreadStatus { /// The thread has finished executing. Dead, - /// The thread is currently running or suspended because it has called `coroutine.yield`. + /// The thread was just created, is currently running or is suspended because it has called + /// `coroutine.yield`. + /// + /// If a thread is in this state, it can be resumed by calling [`Thread::resume`]. + /// + /// [`Thread::resume`]: struct.Thread.html#method.resume Active, - /// The thread has thrown an error during execution. + /// The thread has raised a Lua error during execution. Error, } @@ -1161,13 +1163,22 @@ pub trait UserData: 'static + Sized { fn add_methods(_methods: &mut UserDataMethods) {} } -/// Handle to an internal Lua userdata for any type that implements `UserData`. +/// Handle to an internal Lua userdata for any type that implements [`UserData`]. /// -/// Similar to `std::any::Any`, this provides an interface for dynamic type checking via the `is` -/// and `borrow` methods. +/// Similar to `std::any::Any`, this provides an interface for dynamic type checking via the [`is`] +/// and [`borrow`] methods. /// /// Internally, instances are stored in a `RefCell`, to best match the mutable semantics of the Lua /// language. +/// +/// # Note +/// +/// This API should only be used when necessary. Implementing [`UserData`] already allows defining +/// methods which check the type and acquire a borrow behind the scenes. +/// +/// [`UserData`]: trait.UserData.html +/// [`is`]: #method.is +/// [`borrow`]: #method.borrow #[derive(Clone, Debug)] pub struct AnyUserData<'lua>(LuaRef<'lua>); From ac37b2a0d432170b309e3b10bde1a2c0975a8625 Mon Sep 17 00:00:00 2001 From: kyren Date: Fri, 28 Jul 2017 10:57:19 -0400 Subject: [PATCH 2/2] Small typo fix --- src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index 2fcb838..7e3161b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,7 +12,7 @@ pub enum Error { IncompleteStatement(String), /// Lua runtime error, aka `LUA_ERRRUN`. /// - /// The Lua VM returns this error when a builtin operation is performed on incompatible typed. + /// The Lua VM returns this error when a builtin operation is performed on incompatible types. /// Among other things, this includes invoking operators on wrong types (such as calling or /// indexing a `nil` value). RuntimeError(String),