mlua 0.12.0-rc.1

High level bindings to Lua 5.5/5.4/5.3/5.2/5.1 (including LuaJIT) and Luau with async/await features and support of writing native Lua modules in Rust.
Documentation
## mlua v0.10 release notes

The v0.10 version of mlua has a goal to improve the user experience while keeping the same performance and safety guarantees.
This document highlights the most notable features. For a full list of changes, see the [CHANGELOG].

[CHANGELOG]: https://github.com/mlua-rs/mlua/blob/main/CHANGELOG.md

### New features

#### `'static` Lua types

In previous mlua versions, it was required to have a `'lua` lifetime attached to every Lua value. v0.9 introduced (experimental) owned types that are `'static` without a lifetime attached, but they kept strong references to the Lua instance.
In v0.10 all Lua types are `'static` and have only weak reference to the Lua instance. It means they are more flexible and can be used in more places without worrying about memory leaks.

#### Truly `send` feature

In this version Lua is `Send + Sync` when the `send` feature flag is enabled (previously was only `Send`). It means Lua instance and their values can be safely shared between threads and used in multi threaded async contexts.

```rust
let lua = Lua::new();

lua.globals().set("i", 0)?;
let func = lua.load("i = i + ...").into_function()?;

std::thread::scope(|s| {
    s.spawn(|| {
        for i in 0..5 {
            func.call::<()>(i).unwrap();
        }
    });
    s.spawn(|| {
        for i in 0..5 {
            func.call::<()>(i).unwrap();
        }
    });
});

assert_eq!(lua.globals().get::<i32>("i")?, 20);
```

Under the hood, to synchronize access to the Lua state, mlua uses [`ReentrantMutex`] which can be recursively locked by a single thread. Only one thread can execute Lua code at a time, but it's possible to share Lua values between threads.

This has some performance penalties (about 10-20%) compared to the lock free mode. This flag is disabled by default and is not supported in module mode.

[`ReentrantMutex`]: https://docs.rs/parking_lot/latest/parking_lot/type.ReentrantMutex.html

#### Register Rust functions with variable number of arguments

The new traits `LuaNativeFn`/`LuaNativeFnMut`/`LuaNativeAsyncFn` have been introduced to provide a way to register Rust functions with variable number of arguments in Lua, without needing to pass all arguments as a tuple.

They are used by `Function::wrap`/`Function::wrap_mut`/`Function::wrap_async` methods:

```rust
let add = Function::wrap(|a: i64, b: i64| Ok(a + b));

lua.globals().set("add", add).unwrap();

// Prints 50
lua.load(r#"print(add(5, 45))"#).exec().unwrap();
```

To wrap functions that return direct value (non-`Result`) you can use `Function::wrap_raw` method.

#### Setting metatable for Lua builtin types

For Lua builtin types (like `string`, `function`, `number`, etc.) that have a shared metatable for all instances, it's now possible to set a custom metatable for them.

```rust
let mt = lua.create_table()?;
mt.set("__tostring", lua.create_function(|_, b: bool| Ok(if b { "2" } else { "0" }))?)?;
lua.set_type_metatable::<bool>(Some(mt));
lua.load("assert(tostring(true) == '2')").exec().unwrap();
```

### Improvements

#### New `ObjectLike` trait

The `ObjectLike` trait is a combination of the `AnyUserDataExt` and `TableExt` traits used in previous versions. It provides a unified interface for working with Lua tables and userdata.

#### `Either<L, R>` enum

The `Either<L, R>` enum is a simple enum that can hold either `L` or `R` value. It's useful when you need to return or receive one of two types in a function.
This type implements `IntoLua` and `FromLua` traits and can generate a meaningful error message when conversion fails.

```rust
let func = Function::wrap(|x: Either<i32, String>| Ok(format!("received: {x}")));

lua.globals().set("func", func).unwrap();

// Prints: received: 123
lua.load(r#"print(func(123))"#).exec().unwrap();

// Prints: bad argument #1: error converting Lua table to Either<i32, String>
lua.load(r#"print(pcall(func, {}))"#).exec().unwrap();
```

#### `Lua::exec_raw` helper to execute low-level Lua C API code

For advanced users, it's now possible to execute low-level Lua C API code using the `Lua::exec_raw` method.

```rust
let t = lua.create_sequence_from([1, 2, 3, 4, 5])?;
let sum: i64 = unsafe {
    lua.exec_raw(&t, |state| {
        // top of the stack: table `t`
        let mut sum = 0;
        // push nil as the first key
        mlua::ffi::lua_pushnil(state);
        while mlua::ffi::lua_next(state, -2) != 0 {
            sum += mlua::ffi::lua_tointeger(state, -1);
            // Remove the value, keep the key for the next iteration
            mlua::ffi::lua_pop(state, 1);
        }
        mlua::ffi::lua_pop(state, 1);
        mlua::ffi::lua_pushinteger(state, sum);
        // top of the stack: sum
    })
}?;
assert_eq!(sum, 15);
```

The `exec_raw` method is longjmp-safe. It's not recommended to move `Drop` types into the closure to avoid possible memory leaks.

#### `anyhow` feature flag

The new `anyhow` feature flag adds `IntoLua` and `Into<mlua::Error>` implementation for the `anyhow::Error` type.

```rust
let f = lua.create_function(|_, ()| {
    Err(anyhow!("error message"))?;
    Ok(())
})?;
```

### Breaking changes

#### Scope changes

The following `Scope` methods were changed:
- Removed `Scope::create_any_userdata`
- `Scope::create_nonstatic_userdata` is renamed to `Scope::create_userdata`

Instead, scope has comprehensive support for borrowed userdata: `create_any_userdata_ref`, `create_any_userdata_ref_mut`, `create_userdata_ref`, `create_userdata_ref_mut`.

`UserDataRef` and `UserDataRefMut` are no longer acceptable for scoped userdata access as they require owned underlying data.
In mlua v0.9 this could cause a read-after-free bug in some edge cases.

To temporarily borrow underlying data, the `AnyUserData::borrow_scoped` and `AnyUserData::borrow_mut_scoped` methods were introduced:

```rust
let data = "hello".to_string();
lua.scope(|scope| {
    let ud = scope.create_any_userdata_ref(&data)?;

    // We can only borrow scoped userdata using this method
    ud.borrow_scoped::<String, ()>(|s| {
        assert_eq!(s, "hello");
    })?;

    Ok(())
})?;
```

Those methods work for scoped and regular userdata objects (but still require `T: 'static`).

#### String changes

Since `mlua::String` holds a weak reference to Lua without any guarantees about the lifetime of the underlying data, getting a `&str` or `&[u8]` from it is no longer safe.
Lua instance can be destroyed while reference to the data is still alive:

```rust
let lua = Lua::new();
let s: mlua::String = lua.create_string("hello, world")?; // only weak reference to Lua!
let s_ref: &str = s.to_str()?; // this is not safe!
drop(lua);
println!("{s_ref}"); // use after free!
```

To solve this issue, return types of `mlua::String::to_str` and `mlua::String::as_bytes` methods changed to `BorrowedStr` and `BorrowedBytes` respectively.

These new types hold a strong reference to the Lua instance and can be safely converted to `&str` or `&[u8]`:

```rust
let lua = Lua::new();
let s: mlua::String = lua.create_string("hello, world")?;
let s_ref: mlua::BorrowedStr = s.to_str()?; // The strong reference to Lua is held here
drop(lua);
println!("{s_ref}"); // ok
```

The good news is that `BorrowedStr` implements `Deref<Target = str>`/`AsRef<str>` as well as `Display`, `Debug`, `Eq`, `PartialEq` and other traits for easy usage.
The same applies to `BorrowedBytes`.

Unfortunately, `mlua::String::to_string_lossy` cannot return `Cow<'a, str>` anymore, because it requires a strong reference to Lua. It now returns Rust `String` instead.