Compare commits

..

12 Commits

Author SHA1 Message Date
Alex Orlenko 497d84828a Add CI to build dev docs 2026-02-03 22:40:29 +00:00
Alex Orlenko 0e489901a5 Update debug module
Move debug types from root to new new module.
2026-02-03 22:39:33 +00:00
Alex Orlenko 88063e756f Make table module public 2026-01-30 13:18:46 +00:00
Alex Orlenko c8436e2b80 Make function module public
Reduce number of function-specific types exported to the mlua root and keep
them inside the module.
2026-01-30 13:18:05 +00:00
Alex Orlenko 613748ec16 Use Error::from_lua_conversion helper 2026-01-29 23:09:52 +00:00
Alex Orlenko 2fbd266da6 Remove Error::ToLuaConversionError
This variant used only once and not practically useful.
2026-01-29 23:04:30 +00:00
Alex Orlenko c79b5e9cdb cargo fmt 2026-01-29 23:03:56 +00:00
Alex Orlenko 2ace892613 Rename string::String to LuaString 2026-01-29 18:45:41 +00:00
Alex Orlenko c1ffd4e790 Replace get_or_insert_with with get_or_insert_default 2026-01-29 10:46:58 +00:00
Alex Orlenko d9c139b55f Rust 2024 2026-01-29 10:33:28 +00:00
Alex Orlenko 0c4206c97d Bump min Rust version to 1.88 2026-01-29 10:13:04 +00:00
Alex Orlenko a985dc7a37 Start 0.12.0-dev.1 2026-01-29 10:07:05 +00:00
61 changed files with 946 additions and 770 deletions
+68
View File
@@ -0,0 +1,68 @@
name: Documentation (dev)
on:
push:
branches: [dev]
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment
concurrency:
group: pages
cancel-in-progress: true
jobs:
build:
name: Build Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
- uses: dtolnay/rust-toolchain@nightly
- uses: Swatinem/rust-cache@v2
- name: Build documentation
env:
RUSTDOCFLAGS: "--cfg docsrs"
run: |
cargo +nightly doc --no-deps \
--features "lua55,vendored,async,send,serde,macros,anyhow,userdata-wrappers"
- name: Create index redirect
run: |
echo '<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Redirecting to mlua documentation</title>
<meta http-equiv="refresh" content="0; URL=mlua/index.html">
<link rel="canonical" href="mlua/index.html">
</head>
<body>
<p>Redirecting to <a href="mlua/index.html">mlua documentation</a>...</p>
</body>
</html>' > target/doc/index.html
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v4
with:
path: target/doc
deploy:
name: Deploy to GitHub Pages
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
+3 -4
View File
@@ -1,9 +1,9 @@
[package]
name = "mlua"
version = "0.11.6" # remember to update mlua_derive
version = "0.12.0-dev.1" # remember to update mlua_derive
authors = ["Aleksandr Orlenko <zxteam@pm.me>", "kyren <catherine@kyju.org>"]
rust-version = "1.85.0"
edition = "2021"
rust-version = "1.88"
edition = "2024"
repository = "https://github.com/mlua-rs/mlua"
documentation = "https://docs.rs/mlua"
readme = "README.md"
@@ -61,7 +61,6 @@ erased-serde = { version = "0.4", optional = true }
serde-value = { version = "0.7", optional = true }
parking_lot = { version = "0.12", features = ["arc_lock"] }
anyhow = { version = "1.0", optional = true }
rustversion = "1.0"
libc = "0.2"
ffi = { package = "mlua-sys", version = "0.10.0", path = "mlua-sys" }
+1 -1
View File
@@ -1,7 +1,7 @@
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
use tokio::runtime::Runtime;
use tokio::task;
+1 -1
View File
@@ -1,6 +1,6 @@
use std::time::Duration;
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
use mlua::prelude::*;
+1 -1
View File
@@ -5,7 +5,7 @@ use hyper::body::Incoming;
use hyper_util::client::legacy::Client as HyperClient;
use hyper_util::rt::TokioExecutor;
use mlua::{chunk, ExternalResult, Lua, Result, UserData, UserDataMethods};
use mlua::{ExternalResult, Lua, Result, UserData, UserDataMethods, chunk};
struct BodyReader(Incoming);
+1 -1
View File
@@ -1,4 +1,4 @@
use mlua::{chunk, ExternalResult, Lua, LuaSerdeExt, Result, Value};
use mlua::{ExternalResult, Lua, LuaSerdeExt, Result, Value, chunk};
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<()> {
+1 -1
View File
@@ -11,7 +11,7 @@ use hyper::{Request, Response};
use hyper_util::rt::TokioIo;
use tokio::net::TcpListener;
use mlua::{chunk, Error as LuaError, Function, Lua, String as LuaString, Table, UserData, UserDataMethods};
use mlua::{Error as LuaError, Function, Lua, String as LuaString, Table, UserData, UserDataMethods, chunk};
/// Wrapper around incoming request that implements UserData
struct LuaRequest(SocketAddr, Request<Incoming>);
+1 -1
View File
@@ -4,7 +4,7 @@ use std::net::SocketAddr;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use mlua::{chunk, BString, Function, Lua, UserData, UserDataMethods};
use mlua::{BString, Function, Lua, UserData, UserDataMethods, chunk};
struct LuaTcpStream(TcpStream);
+1 -1
View File
@@ -1,7 +1,7 @@
use std::f32;
use std::iter::FromIterator;
use mlua::{chunk, FromLua, Function, Lua, MetaMethod, Result, UserData, UserDataMethods, Value, Variadic};
use mlua::{FromLua, Function, Lua, MetaMethod, Result, UserData, UserDataMethods, Value, Variadic, chunk};
fn main() -> Result<()> {
// You can create a new Lua state with `Lua::new()`. This loads the default Lua std library
+1 -1
View File
@@ -1,4 +1,4 @@
use mlua::{chunk, Lua, MetaMethod, Result, UserData};
use mlua::{Lua, MetaMethod, Result, UserData, chunk};
#[derive(Default)]
struct Rectangle {
+1 -1
View File
@@ -2,7 +2,7 @@
name = "mlua-sys"
version = "0.10.0"
authors = ["Aleksandr Orlenko <zxteam@pm.me>"]
rust-version = "1.85"
rust-version = "1.88"
edition = "2024"
repository = "https://github.com/mlua-rs/mlua"
documentation = "https://docs.rs/mlua-sys"
+3 -3
View File
@@ -97,7 +97,7 @@ struct BufferCursor(Buffer, usize);
impl io::Read for BufferCursor {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let lua = self.0 .0.lua.lock();
let lua = self.0.0.lua.lock();
let data = self.0.as_slice(&lua);
if self.1 == data.len() {
return Ok(0);
@@ -111,7 +111,7 @@ impl io::Read for BufferCursor {
impl io::Write for BufferCursor {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let lua = self.0 .0.lua.lock();
let lua = self.0.0.lua.lock();
let data = self.0.as_slice_mut(&lua);
if self.1 == data.len() {
return Ok(0);
@@ -129,7 +129,7 @@ impl io::Write for BufferCursor {
impl io::Seek for BufferCursor {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
let lua = self.0 .0.lua.lock();
let lua = self.0.0.lua.lock();
let data = self.0.as_slice(&lua);
let new_offset = match pos {
io::SeekFrom::Start(offset) => offset as i64,
+67 -71
View File
@@ -4,7 +4,6 @@ use std::ffi::CString;
use std::io::Result as IoResult;
use std::panic::Location;
use std::path::{Path, PathBuf};
use std::string::String as StdString;
use crate::error::{Error, Result};
use crate::function::Function;
@@ -20,7 +19,7 @@ pub trait AsChunk {
/// Returns optional chunk name
///
/// See [`Chunk::set_name`] for possible name prefixes.
fn name(&self) -> Option<StdString> {
fn name(&self) -> Option<String> {
None
}
@@ -52,13 +51,13 @@ impl AsChunk for &str {
}
}
impl AsChunk for StdString {
impl AsChunk for String {
fn source<'a>(&self) -> IoResult<Cow<'a, [u8]>> {
Ok(Cow::Owned(self.clone().into_bytes()))
}
}
impl AsChunk for &StdString {
impl AsChunk for &String {
fn source<'a>(&self) -> IoResult<Cow<'a, [u8]>>
where
Self: 'a,
@@ -92,7 +91,7 @@ impl AsChunk for &Vec<u8> {
}
impl AsChunk for &Path {
fn name(&self) -> Option<StdString> {
fn name(&self) -> Option<String> {
Some(format!("@{}", self.display()))
}
@@ -102,7 +101,7 @@ impl AsChunk for &Path {
}
impl AsChunk for PathBuf {
fn name(&self) -> Option<StdString> {
fn name(&self) -> Option<String> {
Some(format!("@{}", self.display()))
}
@@ -112,7 +111,7 @@ impl AsChunk for PathBuf {
}
impl<C: AsChunk + ?Sized> AsChunk for Box<C> {
fn name(&self) -> Option<StdString> {
fn name(&self) -> Option<String> {
(**self).name()
}
@@ -136,7 +135,7 @@ impl<C: AsChunk + ?Sized> AsChunk for Box<C> {
#[must_use = "`Chunk`s do nothing unless one of `exec`, `eval`, `call`, or `into_function` are called on them"]
pub struct Chunk<'a> {
pub(crate) lua: WeakLua,
pub(crate) name: StdString,
pub(crate) name: String,
pub(crate) env: Result<Option<Table>>,
pub(crate) mode: Option<ChunkMode>,
pub(crate) source: IoResult<Cow<'a, [u8]>>,
@@ -160,7 +159,7 @@ pub enum CompileConstant {
Boolean(bool),
Number(crate::Number),
Vector(crate::Vector),
String(StdString),
String(String),
}
#[cfg(any(feature = "luau", doc))]
@@ -192,7 +191,7 @@ impl From<&str> for CompileConstant {
}
#[cfg(any(feature = "luau", doc))]
type LibraryMemberConstantMap = HashMap<(StdString, StdString), CompileConstant>;
type LibraryMemberConstantMap = HashMap<(String, String), CompileConstant>;
/// Luau compiler
#[cfg(any(feature = "luau", doc))]
@@ -203,14 +202,14 @@ pub struct Compiler {
debug_level: u8,
type_info_level: u8,
coverage_level: u8,
vector_lib: Option<StdString>,
vector_ctor: Option<StdString>,
vector_type: Option<StdString>,
mutable_globals: Vec<StdString>,
userdata_types: Vec<StdString>,
libraries_with_known_members: Vec<StdString>,
vector_lib: Option<String>,
vector_ctor: Option<String>,
vector_type: Option<String>,
mutable_globals: Vec<String>,
userdata_types: Vec<String>,
libraries_with_known_members: Vec<String>,
library_constants: Option<LibraryMemberConstantMap>,
disabled_builtins: Vec<StdString>,
disabled_builtins: Vec<String>,
}
#[cfg(any(feature = "luau", doc))]
@@ -294,7 +293,7 @@ impl Compiler {
/// To set the library and method name, use the `lib.ctor` format.
#[doc(hidden)]
#[must_use]
pub fn set_vector_ctor(mut self, ctor: impl Into<StdString>) -> Self {
pub fn set_vector_ctor(mut self, ctor: impl Into<String>) -> Self {
let ctor = ctor.into();
let lib_ctor = ctor.split_once('.');
self.vector_lib = lib_ctor.as_ref().map(|&(lib, _)| lib.to_owned());
@@ -307,7 +306,7 @@ impl Compiler {
/// Sets alternative vector type name for type tables, in addition to default type `vector`.
#[doc(hidden)]
#[must_use]
pub fn set_vector_type(mut self, r#type: impl Into<StdString>) -> Self {
pub fn set_vector_type(mut self, r#type: impl Into<String>) -> Self {
self.vector_type = Some(r#type.into());
self
}
@@ -316,7 +315,7 @@ impl Compiler {
///
/// It disables the import optimization for fields accessed through it.
#[must_use]
pub fn add_mutable_global(mut self, global: impl Into<StdString>) -> Self {
pub fn add_mutable_global(mut self, global: impl Into<String>) -> Self {
self.mutable_globals.push(global.into());
self
}
@@ -325,21 +324,21 @@ impl Compiler {
///
/// It disables the import optimization for fields accessed through these.
#[must_use]
pub fn set_mutable_globals<S: Into<StdString>>(mut self, globals: impl IntoIterator<Item = S>) -> Self {
pub fn set_mutable_globals<S: Into<String>>(mut self, globals: impl IntoIterator<Item = S>) -> Self {
self.mutable_globals = globals.into_iter().map(|s| s.into()).collect();
self
}
/// Adds a userdata type to the list that will be included in the type information.
#[must_use]
pub fn add_userdata_type(mut self, r#type: impl Into<StdString>) -> Self {
pub fn add_userdata_type(mut self, r#type: impl Into<String>) -> Self {
self.userdata_types.push(r#type.into());
self
}
/// Sets a list of userdata types that will be included in the type information.
#[must_use]
pub fn set_userdata_types<S: Into<StdString>>(mut self, types: impl IntoIterator<Item = S>) -> Self {
pub fn set_userdata_types<S: Into<String>>(mut self, types: impl IntoIterator<Item = S>) -> Self {
self.userdata_types = types.into_iter().map(|s| s.into()).collect();
self
}
@@ -366,24 +365,21 @@ impl Compiler {
self.libraries_with_known_members.push(lib.clone());
}
self.library_constants
.get_or_insert_with(HashMap::new)
.get_or_insert_default()
.insert((lib, member), r#const.into());
self
}
/// Adds a builtin that should be disabled.
#[must_use]
pub fn add_disabled_builtin(mut self, builtin: impl Into<StdString>) -> Self {
pub fn add_disabled_builtin(mut self, builtin: impl Into<String>) -> Self {
self.disabled_builtins.push(builtin.into());
self
}
/// Sets a list of builtins that should be disabled.
#[must_use]
pub fn set_disabled_builtins<S: Into<StdString>>(
mut self,
builtins: impl IntoIterator<Item = S>,
) -> Self {
pub fn set_disabled_builtins<S: Into<String>>(mut self, builtins: impl IntoIterator<Item = S>) -> Self {
self.disabled_builtins = builtins.into_iter().map(|s| s.into()).collect();
self
}
@@ -477,11 +473,11 @@ impl Compiler {
options.mutableGlobals = mutable_globals_ptr;
options.userdataTypes = userdata_types_ptr;
options.librariesWithKnownMembers = libraries_with_known_members_ptr;
if let Some(map) = self.library_constants.as_ref() {
if !self.libraries_with_known_members.is_empty() {
LIBRARY_MEMBER_CONSTANT_MAP.with_borrow_mut(|gmap| *gmap = map.clone());
options.libraryMemberConstantCallback = Some(library_member_constant_callback);
}
if let Some(map) = self.library_constants.as_ref()
&& !self.libraries_with_known_members.is_empty()
{
LIBRARY_MEMBER_CONSTANT_MAP.with_borrow_mut(|gmap| *gmap = map.clone());
options.libraryMemberConstantCallback = Some(library_member_constant_callback);
}
options.disabledBuiltins = disabled_builtins_ptr;
ffi::luau_compile(source.as_ref(), options)
@@ -490,7 +486,7 @@ impl Compiler {
if bytecode.first() == Some(&0) {
// The rest of the bytecode is the error message starting with `:`
// See https://github.com/luau-lang/luau/blob/0.640/Compiler/src/Compiler.cpp#L4336
let message = StdString::from_utf8_lossy(&bytecode[2..]).into_owned();
let message = String::from_utf8_lossy(&bytecode[2..]).into_owned();
return Err(Error::SyntaxError {
incomplete_input: message.ends_with("<eof>"),
message,
@@ -513,7 +509,7 @@ impl Chunk<'_> {
/// - `@` - file path (when truncation is needed, the end of the file path is kept, as this is
/// more useful for identifying the file)
/// - `=` - custom chunk name (when truncation is needed, the beginning of the name is kept)
pub fn set_name(mut self, name: impl Into<StdString>) -> Self {
pub fn set_name(mut self, name: impl Into<String>) -> Self {
self.name = name.into();
self
}
@@ -662,19 +658,19 @@ impl Chunk<'_> {
///
/// It does nothing if the chunk is already binary or invalid.
fn compile(&mut self) {
if let Ok(ref source) = self.source {
if self.detect_mode() == ChunkMode::Text {
#[cfg(feature = "luau")]
if let Ok(data) = self.compiler.get_or_insert_with(Default::default).compile(source) {
self.source = Ok(Cow::Owned(data));
self.mode = Some(ChunkMode::Binary);
}
#[cfg(not(feature = "luau"))]
if let Ok(func) = self.lua.lock().load_chunk(None, None, None, source.as_ref()) {
let data = func.dump(false);
self.source = Ok(Cow::Owned(data));
self.mode = Some(ChunkMode::Binary);
}
if let Ok(ref source) = self.source
&& self.detect_mode() == ChunkMode::Text
{
#[cfg(feature = "luau")]
if let Ok(data) = self.compiler.get_or_insert_default().compile(source) {
self.source = Ok(Cow::Owned(data));
self.mode = Some(ChunkMode::Binary);
}
#[cfg(not(feature = "luau"))]
if let Ok(func) = self.lua.lock().load_chunk(None, None, None, source.as_ref()) {
let data = func.dump(false);
self.source = Ok(Cow::Owned(data));
self.mode = Some(ChunkMode::Binary);
}
}
}
@@ -687,33 +683,33 @@ impl Chunk<'_> {
// Try to fetch compiled chunk from cache
let mut text_source = None;
if let Ok(ref source) = self.source {
if self.detect_mode() == ChunkMode::Text {
let lua = self.lua.lock();
if let Some(cache) = lua.priv_app_data_ref::<ChunksCache>() {
if let Some(data) = cache.0.get(source.as_ref()) {
self.source = Ok(Cow::Owned(data.clone()));
self.mode = Some(ChunkMode::Binary);
return self;
}
}
text_source = Some(source.as_ref().to_vec());
if let Ok(ref source) = self.source
&& self.detect_mode() == ChunkMode::Text
{
let lua = self.lua.lock();
if let Some(cache) = lua.priv_app_data_ref::<ChunksCache>()
&& let Some(data) = cache.0.get(source.as_ref())
{
self.source = Ok(Cow::Owned(data.clone()));
self.mode = Some(ChunkMode::Binary);
return self;
}
text_source = Some(source.as_ref().to_vec());
}
// Compile and cache the chunk
if let Some(text_source) = text_source {
self.compile();
if let Ok(ref binary_source) = self.source {
if self.detect_mode() == ChunkMode::Binary {
let lua = self.lua.lock();
if let Some(mut cache) = lua.priv_app_data_mut::<ChunksCache>() {
cache.0.insert(text_source, binary_source.to_vec());
} else {
let mut cache = ChunksCache(HashMap::new());
cache.0.insert(text_source, binary_source.to_vec());
lua.set_priv_app_data(cache);
};
if let Ok(ref binary_source) = self.source
&& self.detect_mode() == ChunkMode::Binary
{
let lua = self.lua.lock();
if let Some(mut cache) = lua.priv_app_data_mut::<ChunksCache>() {
cache.0.insert(text_source, binary_source.to_vec());
} else {
let mut cache = ChunksCache(HashMap::new());
cache.0.insert(text_source, binary_source.to_vec());
lua.set_priv_app_data(cache);
}
}
}
@@ -761,7 +757,7 @@ impl Chunk<'_> {
ChunkMode::Text
}
fn convert_name(name: StdString) -> Result<CString> {
fn convert_name(name: String) -> Result<CString> {
CString::new(name).map_err(|err| Error::runtime(format!("invalid name: {err}")))
}
+118 -196
View File
@@ -4,16 +4,15 @@ use std::ffi::{CStr, CString, OsStr, OsString};
use std::hash::{BuildHasher, Hash};
use std::os::raw::c_int;
use std::path::{Path, PathBuf};
use std::string::String as StdString;
use std::{mem, slice, str};
use bstr::{BStr, BString, ByteSlice, ByteVec};
use bstr::{BStr, BString, ByteVec};
use num_traits::cast;
use crate::error::{Error, Result};
use crate::function::Function;
use crate::state::{Lua, RawLua};
use crate::string::{BorrowedBytes, BorrowedStr, String};
use crate::string::{BorrowedBytes, BorrowedStr, LuaString};
use crate::table::Table;
use crate::thread::Thread;
use crate::traits::{FromLua, IntoLua, ShortTypeName as _};
@@ -47,14 +46,14 @@ impl FromLua for Value {
}
}
impl IntoLua for String {
impl IntoLua for LuaString {
#[inline]
fn into_lua(self, _: &Lua) -> Result<Value> {
Ok(Value::String(self))
}
}
impl IntoLua for &String {
impl IntoLua for &LuaString {
#[inline]
fn into_lua(self, _: &Lua) -> Result<Value> {
Ok(Value::String(self.clone()))
@@ -67,16 +66,12 @@ impl IntoLua for &String {
}
}
impl FromLua for String {
impl FromLua for LuaString {
#[inline]
fn from_lua(value: Value, lua: &Lua) -> Result<String> {
fn from_lua(value: Value, lua: &Lua) -> Result<LuaString> {
let ty = value.type_name();
lua.coerce_string(value)?
.ok_or_else(|| Error::FromLuaConversionError {
from: ty,
to: "string".to_string(),
message: Some("expected string or number".to_string()),
})
.ok_or_else(|| Error::from_lua_conversion(ty, "string", "expected string or number".to_string()))
}
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
@@ -84,7 +79,7 @@ impl FromLua for String {
let type_id = ffi::lua_type(state, idx);
if type_id == ffi::LUA_TSTRING {
ffi::lua_xpush(state, lua.ref_thread(), idx);
return Ok(String(lua.pop_ref_thread()));
return Ok(LuaString(lua.pop_ref_thread()));
}
// Fallback to default
Self::from_lua(lua.stack_value(idx, Some(type_id)), lua.lua())
@@ -119,7 +114,7 @@ impl IntoLua for &BorrowedStr<'_> {
impl FromLua for BorrowedStr<'_> {
fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
let s = String::from_lua(value, lua)?;
let s = LuaString::from_lua(value, lua)?;
let BorrowedStr { buf, _lua, .. } = BorrowedStr::try_from(&s)?;
let buf = unsafe { mem::transmute::<&str, &'static str>(buf) };
let borrow = Cow::Owned(s);
@@ -127,7 +122,7 @@ impl FromLua for BorrowedStr<'_> {
}
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
let s = String::from_stack(idx, lua)?;
let s = LuaString::from_stack(idx, lua)?;
let BorrowedStr { buf, _lua, .. } = BorrowedStr::try_from(&s)?;
let buf = unsafe { mem::transmute::<&str, &'static str>(buf) };
let borrow = Cow::Owned(s);
@@ -163,7 +158,7 @@ impl IntoLua for &BorrowedBytes<'_> {
impl FromLua for BorrowedBytes<'_> {
fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
let s = String::from_lua(value, lua)?;
let s = LuaString::from_lua(value, lua)?;
let BorrowedBytes { buf, _lua, .. } = BorrowedBytes::from(&s);
let buf = unsafe { mem::transmute::<&[u8], &'static [u8]>(buf) };
let borrow = Cow::Owned(s);
@@ -171,7 +166,7 @@ impl FromLua for BorrowedBytes<'_> {
}
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
let s = String::from_stack(idx, lua)?;
let s = LuaString::from_stack(idx, lua)?;
let BorrowedBytes { buf, _lua, .. } = BorrowedBytes::from(&s);
let buf = unsafe { mem::transmute::<&[u8], &'static [u8]>(buf) };
let borrow = Cow::Owned(s);
@@ -204,11 +199,7 @@ impl FromLua for Table {
fn from_lua(value: Value, _: &Lua) -> Result<Table> {
match value {
Value::Table(table) => Ok(table),
_ => Err(Error::FromLuaConversionError {
from: value.type_name(),
to: "table".to_string(),
message: None,
}),
_ => Err(Error::from_lua_conversion(value.type_name(), "table", None)),
}
}
}
@@ -238,11 +229,7 @@ impl FromLua for Function {
fn from_lua(value: Value, _: &Lua) -> Result<Function> {
match value {
Value::Function(table) => Ok(table),
_ => Err(Error::FromLuaConversionError {
from: value.type_name(),
to: "function".to_string(),
message: None,
}),
_ => Err(Error::from_lua_conversion(value.type_name(), "function", None)),
}
}
}
@@ -272,11 +259,7 @@ impl FromLua for Thread {
fn from_lua(value: Value, _: &Lua) -> Result<Thread> {
match value {
Value::Thread(t) => Ok(t),
_ => Err(Error::FromLuaConversionError {
from: value.type_name(),
to: "thread".to_string(),
message: None,
}),
_ => Err(Error::from_lua_conversion(value.type_name(), "thread", None)),
}
}
}
@@ -306,11 +289,7 @@ impl FromLua for AnyUserData {
fn from_lua(value: Value, _: &Lua) -> Result<AnyUserData> {
match value {
Value::UserData(ud) => Ok(ud),
_ => Err(Error::FromLuaConversionError {
from: value.type_name(),
to: "userdata".to_string(),
message: None,
}),
_ => Err(Error::from_lua_conversion(value.type_name(), "userdata", None)),
}
}
}
@@ -428,11 +407,11 @@ impl FromLua for LightUserData {
fn from_lua(value: Value, _: &Lua) -> Result<Self> {
match value {
Value::LightUserData(ud) => Ok(ud),
_ => Err(Error::FromLuaConversionError {
from: value.type_name(),
to: "lightuserdata".to_string(),
message: None,
}),
_ => Err(Error::from_lua_conversion(
value.type_name(),
"lightuserdata",
None,
)),
}
}
}
@@ -451,11 +430,7 @@ impl FromLua for crate::Vector {
fn from_lua(value: Value, _: &Lua) -> Result<Self> {
match value {
Value::Vector(v) => Ok(v),
_ => Err(Error::FromLuaConversionError {
from: value.type_name(),
to: "vector".to_string(),
message: None,
}),
_ => Err(Error::from_lua_conversion(value.type_name(), "vector", None)),
}
}
}
@@ -488,16 +463,12 @@ impl FromLua for crate::Buffer {
fn from_lua(value: Value, _: &Lua) -> Result<Self> {
match value {
Value::Buffer(buf) => Ok(buf),
_ => Err(Error::FromLuaConversionError {
from: value.type_name(),
to: "buffer".to_string(),
message: None,
}),
_ => Err(Error::from_lua_conversion(value.type_name(), "buffer", None)),
}
}
}
impl IntoLua for StdString {
impl IntoLua for String {
#[inline]
fn into_lua(self, lua: &Lua) -> Result<Value> {
#[cfg(feature = "lua55")]
@@ -519,16 +490,14 @@ impl IntoLua for StdString {
}
}
impl FromLua for StdString {
impl FromLua for String {
#[inline]
fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
let ty = value.type_name();
Ok(lua
.coerce_string(value)?
.ok_or_else(|| Error::FromLuaConversionError {
from: ty,
to: Self::type_name(),
message: Some("expected string or number".to_string()),
.ok_or_else(|| {
Error::from_lua_conversion(ty, Self::type_name(), "expected string or number".to_string())
})?
.to_str()?
.to_owned())
@@ -544,11 +513,7 @@ impl FromLua for StdString {
let bytes = slice::from_raw_parts(data as *const u8, size);
return str::from_utf8(bytes)
.map(|s| s.to_owned())
.map_err(|e| Error::FromLuaConversionError {
from: "string",
to: Self::type_name(),
message: Some(e.to_string()),
});
.map_err(|e| Error::from_lua_conversion("string", Self::type_name(), e.to_string()));
}
// Fallback to default
Self::from_lua(lua.stack_value(idx, Some(type_id)), lua.lua())
@@ -587,10 +552,8 @@ impl FromLua for Box<str> {
let ty = value.type_name();
Ok(lua
.coerce_string(value)?
.ok_or_else(|| Error::FromLuaConversionError {
from: ty,
to: Self::type_name(),
message: Some("expected string or number".to_string()),
.ok_or_else(|| {
Error::from_lua_conversion(ty, Self::type_name(), "expected string or number".to_string())
})?
.to_str()?
.to_owned()
@@ -614,21 +577,12 @@ impl FromLua for CString {
#[inline]
fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
let ty = value.type_name();
let string = lua
.coerce_string(value)?
.ok_or_else(|| Error::FromLuaConversionError {
from: ty,
to: Self::type_name(),
message: Some("expected string or number".to_string()),
})?;
let string = lua.coerce_string(value)?.ok_or_else(|| {
Error::from_lua_conversion(ty, Self::type_name(), "expected string or number".to_string())
})?;
match CStr::from_bytes_with_nul(&string.as_bytes_with_nul()) {
Ok(s) => Ok(s.into()),
Err(_) => Err(Error::FromLuaConversionError {
from: ty,
to: Self::type_name(),
message: Some("invalid C-style string".to_string()),
}),
Err(err) => Err(Error::from_lua_conversion(ty, Self::type_name(), err.to_string())),
}
}
}
@@ -668,10 +622,8 @@ impl FromLua for BString {
Value::Buffer(buf) => Ok(buf.to_vec().into()),
_ => Ok((*lua
.coerce_string(value)?
.ok_or_else(|| Error::FromLuaConversionError {
from: ty,
to: Self::type_name(),
message: Some("expected string or number".to_string()),
.ok_or_else(|| {
Error::from_lua_conversion(ty, Self::type_name(), "expected string or number".to_string())
})?
.as_bytes())
.into()),
@@ -722,23 +674,22 @@ impl FromLua for OsString {
let bs = BString::from_lua(value, lua)?;
Vec::from(bs)
.into_os_string()
.map_err(|err| Error::FromLuaConversionError {
from: ty,
to: "OsString".into(),
message: Some(err.to_string()),
})
.map_err(|err| Error::from_lua_conversion(ty, "OsString", err.to_string()))
}
}
impl IntoLua for &OsStr {
#[cfg(unix)]
#[inline]
fn into_lua(self, lua: &Lua) -> Result<Value> {
let s = <[u8]>::from_os_str(self).ok_or_else(|| Error::ToLuaConversionError {
from: "OsStr".into(),
to: "string",
message: Some("invalid utf-8 encoding".into()),
})?;
Ok(Value::String(lua.create_string(s)?))
use std::os::unix::ffi::OsStrExt;
Ok(Value::String(lua.create_string(self.as_bytes())?))
}
#[cfg(not(unix))]
#[inline]
fn into_lua(self, lua: &Lua) -> Result<Value> {
self.display().to_string().into_lua(lua)
}
}
@@ -776,34 +727,25 @@ impl FromLua for char {
fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
let ty = value.type_name();
match value {
Value::Integer(i) => {
cast(i)
.and_then(char::from_u32)
.ok_or_else(|| Error::FromLuaConversionError {
from: ty,
to: "char".to_string(),
message: Some("integer out of range when converting to char".to_string()),
})
}
Value::Integer(i) => cast(i).and_then(char::from_u32).ok_or_else(|| {
let msg = "integer out of range when converting to char";
Error::from_lua_conversion(ty, "char", msg.to_string())
}),
Value::String(s) => {
let str = s.to_str()?;
let mut str_iter = str.chars();
match (str_iter.next(), str_iter.next()) {
(Some(char), None) => Ok(char),
_ => Err(Error::FromLuaConversionError {
from: ty,
to: "char".to_string(),
message: Some(
"expected string to have exactly one char when converting to char".to_string(),
),
}),
_ => {
let msg = "expected string to have exactly one char when converting to char";
Err(Error::from_lua_conversion(ty, "char", msg.to_string()))
}
}
}
_ => Err(Error::FromLuaConversionError {
from: ty,
to: Self::type_name(),
message: Some("expected string or integer".to_string()),
}),
_ => {
let msg = "expected string or integer";
Err(Error::from_lua_conversion(ty, Self::type_name(), msg.to_string()))
}
}
}
}
@@ -854,24 +796,14 @@ macro_rules! lua_convert_int {
if let Some(i) = lua.coerce_integer(value.clone())? {
cast(i)
} else {
cast(
lua.coerce_number(value)?
.ok_or_else(|| Error::FromLuaConversionError {
from: ty,
to: stringify!($x).to_string(),
message: Some(
"expected number or string coercible to number".to_string(),
),
})?,
)
cast(lua.coerce_number(value)?.ok_or_else(|| {
let msg = "expected number or string coercible to number";
Error::from_lua_conversion(ty, stringify!($x), msg.to_string())
})?)
}
}
})
.ok_or_else(|| Error::FromLuaConversionError {
from: ty,
to: stringify!($x).to_string(),
message: Some("out of range".to_owned()),
})
.ok_or_else(|| Error::from_lua_conversion(ty, stringify!($x), "out of range".to_string()))
}
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
@@ -881,10 +813,8 @@ macro_rules! lua_convert_int {
let mut ok = 0;
let i = ffi::lua_tointegerx(state, idx, &mut ok);
if ok != 0 {
return cast(i).ok_or_else(|| Error::FromLuaConversionError {
from: "integer",
to: stringify!($x).to_string(),
message: Some("out of range".to_owned()),
return cast(i).ok_or_else(|| {
Error::from_lua_conversion("integer", stringify!($x), "out of range".to_string())
});
}
}
@@ -921,13 +851,10 @@ macro_rules! lua_convert_float {
#[inline]
fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
let ty = value.type_name();
lua.coerce_number(value)?
.map(|n| n as $x)
.ok_or_else(|| Error::FromLuaConversionError {
from: ty,
to: stringify!($x).to_string(),
message: Some("expected number or string coercible to number".to_string()),
})
lua.coerce_number(value)?.map(|n| n as $x).ok_or_else(|| {
let msg = "expected number or string coercible to number";
Error::from_lua_conversion(ty, stringify!($x), msg.to_string())
})
}
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
@@ -987,18 +914,16 @@ where
},
Value::Table(table) => {
let vec = table.sequence_values().collect::<Result<Vec<_>>>()?;
vec.try_into()
.map_err(|vec: Vec<T>| Error::FromLuaConversionError {
from: "table",
to: Self::type_name(),
message: Some(format!("expected table of length {N}, got {}", vec.len())),
})
vec.try_into().map_err(|vec: Vec<T>| {
let msg = format!("expected table of length {N}, got {}", vec.len());
Error::from_lua_conversion("table", Self::type_name(), msg)
})
}
_ => {
let msg = format!("expected table of length {N}");
let err = Error::from_lua_conversion(value.type_name(), Self::type_name(), msg.to_string());
Err(err)
}
_ => Err(Error::FromLuaConversionError {
from: value.type_name(),
to: Self::type_name(),
message: Some("expected table".to_string()),
}),
}
}
}
@@ -1029,11 +954,11 @@ impl<T: FromLua> FromLua for Vec<T> {
fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
match value {
Value::Table(table) => table.sequence_values().collect(),
_ => Err(Error::FromLuaConversionError {
from: value.type_name(),
to: Self::type_name(),
message: Some("expected table".to_string()),
}),
_ => Err(Error::from_lua_conversion(
value.type_name(),
Self::type_name(),
"expected table".to_string(),
)),
}
}
}
@@ -1048,14 +973,13 @@ impl<K: Eq + Hash + IntoLua, V: IntoLua, S: BuildHasher> IntoLua for HashMap<K,
impl<K: Eq + Hash + FromLua, V: FromLua, S: BuildHasher + Default> FromLua for HashMap<K, V, S> {
#[inline]
fn from_lua(value: Value, _: &Lua) -> Result<Self> {
if let Value::Table(table) = value {
table.pairs().collect()
} else {
Err(Error::FromLuaConversionError {
from: value.type_name(),
to: Self::type_name(),
message: Some("expected table".to_string()),
})
match value {
Value::Table(table) => table.pairs().collect(),
_ => Err(Error::from_lua_conversion(
value.type_name(),
Self::type_name(),
"expected table".to_string(),
)),
}
}
}
@@ -1070,14 +994,13 @@ impl<K: Ord + IntoLua, V: IntoLua> IntoLua for BTreeMap<K, V> {
impl<K: Ord + FromLua, V: FromLua> FromLua for BTreeMap<K, V> {
#[inline]
fn from_lua(value: Value, _: &Lua) -> Result<Self> {
if let Value::Table(table) = value {
table.pairs().collect()
} else {
Err(Error::FromLuaConversionError {
from: value.type_name(),
to: Self::type_name(),
message: Some("expected table".to_string()),
})
match value {
Value::Table(table) => table.pairs().collect(),
_ => Err(Error::from_lua_conversion(
value.type_name(),
Self::type_name(),
"expected table".to_string(),
)),
}
}
}
@@ -1097,11 +1020,11 @@ impl<T: Eq + Hash + FromLua, S: BuildHasher + Default> FromLua for HashSet<T, S>
match value {
Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(),
Value::Table(table) => table.pairs::<T, Value>().map(|res| res.map(|(k, _)| k)).collect(),
_ => Err(Error::FromLuaConversionError {
from: value.type_name(),
to: Self::type_name(),
message: Some("expected table".to_string()),
}),
_ => Err(Error::from_lua_conversion(
value.type_name(),
Self::type_name(),
"expected table".to_string(),
)),
}
}
}
@@ -1121,11 +1044,11 @@ impl<T: Ord + FromLua> FromLua for BTreeSet<T> {
match value {
Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(),
Value::Table(table) => table.pairs::<T, Value>().map(|res| res.map(|(k, _)| k)).collect(),
_ => Err(Error::FromLuaConversionError {
from: value.type_name(),
to: Self::type_name(),
message: Some("expected table".to_string()),
}),
_ => Err(Error::from_lua_conversion(
value.type_name(),
Self::type_name(),
"expected table".to_string(),
)),
}
}
}
@@ -1195,11 +1118,11 @@ impl<L: FromLua, R: FromLua> FromLua for Either<L, R> {
// Try the right type
Err(_) => match R::from_lua(value, lua).map(Either::Right) {
Ok(r) => Ok(r),
Err(_) => Err(Error::FromLuaConversionError {
from: value_type_name,
to: Self::type_name(),
message: None,
}),
Err(_) => Err(Error::from_lua_conversion(
value_type_name,
Self::type_name(),
None,
)),
},
}
}
@@ -1211,13 +1134,12 @@ impl<L: FromLua, R: FromLua> FromLua for Either<L, R> {
Err(_) => match R::from_stack(idx, lua).map(Either::Right) {
Ok(r) => Ok(r),
Err(_) => {
let value_type_name =
CStr::from_ptr(ffi::lua_typename(lua.state(), ffi::lua_type(lua.state(), idx)));
Err(Error::FromLuaConversionError {
from: value_type_name.to_str().unwrap(),
to: Self::type_name(),
message: None,
})
let state = lua.state();
let from_type_name = CStr::from_ptr(ffi::lua_typename(state, ffi::lua_type(state, idx)))
.to_str()
.unwrap_or("unknown");
let err = Error::from_lua_conversion(from_type_name, Self::type_name(), None);
Err(err)
}
},
}
+32 -49
View File
@@ -1,3 +1,9 @@
//! Lua debugging interface.
//!
//! This module provides access to the Lua debug interface, allowing inspection of the call stack,
//! and function information. The main types are [`Debug`] for accessing debug information and
//! [`HookTriggers`] for configuring debug hooks.
use std::borrow::Cow;
use std::os::raw::c_int;
@@ -5,7 +11,7 @@ use ffi::{lua_Debug, lua_State};
use crate::function::Function;
use crate::state::RawLua;
use crate::util::{assert_stack, linenumber_to_usize, ptr_to_lossy_str, ptr_to_str, StackGuard};
use crate::util::{StackGuard, assert_stack, linenumber_to_usize, ptr_to_lossy_str, ptr_to_str};
/// Contains information about currently executing Lua code.
///
@@ -133,12 +139,6 @@ impl<'a> Debug<'a> {
}
}
#[doc(hidden)]
#[deprecated(note = "Use `current_line` instead")]
pub fn curr_line(&self) -> i32 {
self.current_line().map(|n| n as i32).unwrap_or(-1)
}
/// Corresponds to the `l` "what" mask. Returns the current line.
pub fn current_line(&self) -> Option<usize> {
unsafe {
@@ -190,15 +190,15 @@ impl<'a> Debug<'a> {
#[cfg(not(feature = "luau"))]
let stack = DebugStack {
num_ups: (*self.ar).nups as _,
#[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
num_upvalues: (*self.ar).nups as _,
#[cfg(not(any(feature = "lua51", feature = "luajit")))]
num_params: (*self.ar).nparams as _,
#[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
#[cfg(not(any(feature = "lua51", feature = "luajit")))]
is_vararg: (*self.ar).isvararg != 0,
};
#[cfg(feature = "luau")]
let stack = DebugStack {
num_ups: (*self.ar).nupvals,
num_upvalues: (*self.ar).nupvals,
num_params: (*self.ar).nparams,
is_vararg: (*self.ar).isvararg != 0,
};
@@ -208,6 +208,8 @@ impl<'a> Debug<'a> {
}
/// Represents a specific event that triggered the hook.
#[cfg(not(feature = "luau"))]
#[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DebugEvent {
Call,
@@ -218,6 +220,9 @@ pub enum DebugEvent {
Unknown(c_int),
}
/// Contains the name information of a function in the call stack.
///
/// Returned by the [`Debug::names`] method.
#[derive(Clone, Debug)]
pub struct DebugNames<'a> {
/// A (reasonable) name of the function (`None` if the name cannot be found).
@@ -228,6 +233,9 @@ pub struct DebugNames<'a> {
pub name_what: Option<&'static str>,
}
/// Contains the source information of a function in the call stack.
///
/// Returned by the [`Debug::source`] method.
#[derive(Clone, Debug)]
pub struct DebugSource<'a> {
/// Source of the chunk that created the function.
@@ -243,47 +251,20 @@ pub struct DebugSource<'a> {
pub what: &'static str,
}
/// Contains stack information about a function in the call stack.
///
/// Returned by the [`Debug::stack`] method.
#[derive(Copy, Clone, Debug)]
pub struct DebugStack {
/// Number of upvalues.
pub num_ups: u8,
/// Number of parameters.
#[cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
))]
#[cfg_attr(
docsrs,
doc(cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
)))
)]
/// The number of upvalues of the function.
pub num_upvalues: u8,
/// The number of parameters of the function (always 0 for C).
#[cfg(any(not(any(feature = "lua51", feature = "luajit")), doc))]
#[cfg_attr(docsrs, doc(cfg(not(any(feature = "lua51", feature = "luajit")))))]
pub num_params: u8,
/// Whether the function is a vararg function.
#[cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
))]
#[cfg_attr(
docsrs,
doc(cfg(any(
feature = "lua55",
feature = "lua54",
feature = "lua53",
feature = "lua52",
feature = "luau"
)))
)]
/// Whether the function is a variadic function (always true for C).
#[cfg(any(not(any(feature = "lua51", feature = "luajit")), doc))]
#[cfg_attr(docsrs, doc(cfg(not(any(feature = "lua51", feature = "luajit")))))]
pub is_vararg: bool,
}
@@ -361,6 +342,7 @@ impl HookTriggers {
}
// Compute the mask to pass to `lua_sethook`.
#[cfg(not(feature = "luau"))]
pub(crate) const fn mask(&self) -> c_int {
let mut mask: c_int = 0;
if self.on_calls {
@@ -380,6 +362,7 @@ impl HookTriggers {
// Returns the `count` parameter to pass to `lua_sethook`, if applicable. Otherwise, zero is
// returned.
#[cfg(not(feature = "luau"))]
pub(crate) const fn count(&self) -> c_int {
match self.every_nth_instruction {
Some(n) => n as c_int,
+30 -41
View File
@@ -4,7 +4,6 @@ use std::io::Error as IoError;
use std::net::AddrParseError;
use std::result::Result as StdResult;
use std::str::Utf8Error;
use std::string::String as StdString;
use std::sync::Arc;
use crate::private::Sealed;
@@ -22,7 +21,7 @@ pub enum Error {
/// Syntax error while parsing Lua source code.
SyntaxError {
/// The error message as returned by Lua.
message: StdString,
message: String,
/// `true` if the error can likely be fixed by appending more input to the source code.
///
/// This is useful for implementing REPLs as they can query the user for more input if this
@@ -34,20 +33,20 @@ pub enum Error {
/// 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(StdString),
RuntimeError(String),
/// Lua memory error, aka `LUA_ERRMEM`
///
/// The Lua VM returns this error when the allocator does not return the requested memory, aka
/// it is an out-of-memory error.
MemoryError(StdString),
MemoryError(String),
/// Lua garbage collector error, aka `LUA_ERRGCMM`.
///
/// The Lua VM returns this error when there is an error running a `__gc` metamethod.
#[cfg(any(feature = "lua53", feature = "lua52", doc))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua53", feature = "lua52"))))]
GarbageCollectorError(StdString),
GarbageCollectorError(String),
/// Potentially unsafe action in safe mode.
SafetyError(StdString),
SafetyError(String),
/// Memory control is not available.
///
/// This error can only happen when Lua state was not created by us and does not have the
@@ -80,23 +79,14 @@ pub enum Error {
/// (which is stored in the corresponding field).
BadArgument {
/// Function that was called.
to: Option<StdString>,
to: Option<String>,
/// Argument position (usually starts from 1).
pos: usize,
/// Argument name.
name: Option<StdString>,
name: Option<String>,
/// Underlying error returned when converting argument to a Lua value.
cause: Arc<Error>,
},
/// A Rust value could not be converted to a Lua value.
ToLuaConversionError {
/// Name of the Rust type that could not be converted.
from: String,
/// Name of the Lua type that could not be created.
to: &'static str,
/// A message indicating why the conversion failed in more detail.
message: Option<StdString>,
},
/// A Lua value could not be converted to the expected Rust type.
FromLuaConversionError {
/// Name of the Lua type that could not be converted.
@@ -104,7 +94,7 @@ pub enum Error {
/// Name of the Rust type that could not be created.
to: String,
/// A string containing more detailed error information.
message: Option<StdString>,
message: Option<String>,
},
/// [`Thread::resume`] was called on an unresumable coroutine.
///
@@ -154,17 +144,17 @@ pub enum Error {
/// A [`MetaMethod`] operation is restricted (typically for `__gc` or `__metatable`).
///
/// [`MetaMethod`]: crate::MetaMethod
MetaMethodRestricted(StdString),
MetaMethodRestricted(String),
/// A [`MetaMethod`] (eg. `__index` or `__newindex`) has invalid type.
///
/// [`MetaMethod`]: crate::MetaMethod
MetaMethodTypeError {
/// Name of the metamethod.
method: StdString,
method: String,
/// Passed value type.
type_name: &'static str,
/// A string containing more detailed error information.
message: Option<StdString>,
message: Option<String>,
},
/// A [`RegistryKey`] produced from a different Lua state was used.
///
@@ -173,7 +163,7 @@ pub enum Error {
/// A Rust callback returned `Err`, raising the contained `Error` as a Lua error.
CallbackError {
/// Lua call stack backtrace.
traceback: StdString,
traceback: String,
/// Original error returned by the Rust code.
cause: Arc<Error>,
},
@@ -185,11 +175,11 @@ pub enum Error {
/// Serialization error.
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
SerializeError(StdString),
SerializeError(String),
/// Deserialization error.
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
DeserializeError(StdString),
DeserializeError(String),
/// A custom error.
///
/// This can be used for returning user-defined errors from callbacks.
@@ -201,7 +191,7 @@ pub enum Error {
/// An error with additional context.
WithContext {
/// A string containing additional context.
context: StdString,
context: String,
/// Underlying error.
cause: Arc<Error>,
},
@@ -225,7 +215,7 @@ impl fmt::Display for Error {
}
Error::SafetyError(msg) => {
write!(fmt, "safety error: {msg}")
},
}
Error::MemoryControlNotAvailable => {
write!(fmt, "memory control is not available")
}
@@ -238,10 +228,7 @@ impl fmt::Display for Error {
fmt,
"out of Lua stack, too many arguments to a Lua function or too many return values from a callback"
),
Error::BindError => write!(
fmt,
"too many arguments to Function::bind"
),
Error::BindError => write!(fmt, "too many arguments to Function::bind"),
Error::BadArgument { to, pos, name, cause } => {
if let Some(name) = name {
write!(fmt, "bad argument `{name}`")?;
@@ -252,13 +239,6 @@ impl fmt::Display for Error {
write!(fmt, " to `{to}`")?;
}
write!(fmt, ": {cause}")
},
Error::ToLuaConversionError { from, to, message } => {
write!(fmt, "error converting {from} to Lua {to}")?;
match message {
None => Ok(()),
Some(message) => write!(fmt, " ({message})"),
}
}
Error::FromLuaConversionError { from, to, message } => {
write!(fmt, "error converting Lua {from} to {to}")?;
@@ -273,7 +253,11 @@ impl fmt::Display for Error {
Error::UserDataBorrowError => write!(fmt, "error borrowing userdata"),
Error::UserDataBorrowMutError => write!(fmt, "error mutably borrowing userdata"),
Error::MetaMethodRestricted(method) => write!(fmt, "metamethod {method} is restricted"),
Error::MetaMethodTypeError { method, type_name, message } => {
Error::MetaMethodTypeError {
method,
type_name,
message,
} => {
write!(fmt, "metamethod {method} has unsupported type {type_name}")?;
match message {
None => Ok(()),
@@ -286,7 +270,11 @@ impl fmt::Display for Error {
Error::CallbackError { cause, traceback } => {
// Trace errors down to the root
let (mut cause, mut full_traceback) = (cause, None);
while let Error::CallbackError { cause: cause2, traceback: traceback2 } = &**cause {
while let Error::CallbackError {
cause: cause2,
traceback: traceback2,
} = &**cause
{
cause = cause2;
full_traceback = Some(traceback2);
}
@@ -312,11 +300,11 @@ impl fmt::Display for Error {
#[cfg(feature = "serde")]
Error::SerializeError(err) => {
write!(fmt, "serialize error: {err}")
},
}
#[cfg(feature = "serde")]
Error::DeserializeError(err) => {
write!(fmt, "deserialize error: {err}")
},
}
Error::ExternalError(err) => err.fmt(fmt),
Error::WithContext { context, cause } => {
writeln!(fmt, "{context}")?;
@@ -394,6 +382,7 @@ impl Error {
}
}
#[inline]
pub(crate) fn from_lua_conversion(
from: &'static str,
to: impl ToString,
+85 -2
View File
@@ -1,3 +1,84 @@
//! Lua function handling.
//!
//! This module provides types for working with Lua functions from Rust, including
//! both Lua-defined functions and native Rust callbacks.
//!
//! # Main Types
//!
//! - [`Function`] - A handle to a Lua function that can be called from Rust.
//! - [`FunctionInfo`] - Debug information about a function (name, source, line numbers, etc.).
//! - [`CoverageInfo`] - Code coverage data for Luau functions (requires `luau` feature).
//!
//! # Calling Functions
//!
//! Use [`Function::call`] to invoke a Lua function synchronously:
//!
//! ```
//! # use mlua::{Function, Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//!
//! // Get a built-in function
//! let print: Function = lua.globals().get("print")?;
//! print.call::<()>("Hello from Rust!")?;
//!
//! // Call a function that returns values
//! let tonumber: Function = lua.globals().get("tonumber")?;
//! let n: i32 = tonumber.call("42")?;
//! assert_eq!(n, 42);
//! # Ok(())
//! # }
//! ```
//!
//! For asynchronous execution, use `Function::call_async` (requires `async` feature):
//!
//! ```ignore
//! let result: String = my_async_func.call_async(args).await?;
//! ```
//!
//! # Creating Functions
//!
//! Functions can be created from Rust closures using [`Lua::create_function`]:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//!
//! let greet = lua.create_function(|_, name: String| {
//! Ok(format!("Hello, {}!", name))
//! })?;
//!
//! lua.globals().set("greet", greet)?;
//! let result: String = lua.load(r#"greet("World")"#).eval()?;
//! assert_eq!(result, "Hello, World!");
//! # Ok(())
//! # }
//! ```
//!
//! For simpler cases, use [`Function::wrap`] or [`Function::wrap_raw`] to convert a Rust function
//! directly:
//!
//! ```
//! # use mlua::{Function, Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//!
//! fn add(a: i32, b: i32) -> i32 { a + b }
//!
//! lua.globals().set("add", Function::wrap_raw(add))?;
//! let sum: i32 = lua.load("add(2, 3)").eval()?;
//! assert_eq!(sum, 5);
//! # Ok(())
//! # }
//! ```
//!
//! # Function Environments
//!
//! Lua functions have an associated environment table that determines how global
//! variables are resolved. Use [`Function::environment`] and [`Function::set_environment`]
//! to inspect or modify this environment.
use std::cell::RefCell;
use std::os::raw::{c_int, c_void};
use std::{mem, ptr, slice};
@@ -8,7 +89,7 @@ use crate::table::Table;
use crate::traits::{FromLuaMulti, IntoLua, IntoLuaMulti, LuaNativeFn, LuaNativeFnMut};
use crate::types::{Callback, LuaType, MaybeSend, ValueRef};
use crate::util::{
assert_stack, check_stack, linenumber_to_usize, pop_error, ptr_to_lossy_str, ptr_to_str, StackGuard,
StackGuard, assert_stack, check_stack, linenumber_to_usize, pop_error, ptr_to_lossy_str, ptr_to_str,
};
use crate::value::Value;
@@ -18,7 +99,7 @@ use {
crate::traits::LuaNativeAsyncFn,
crate::types::AsyncCallback,
std::future::{self, Future},
std::pin::{pin, Pin},
std::pin::{Pin, pin},
std::task::{Context, Poll},
};
@@ -681,7 +762,9 @@ impl LuaType for Function {
const TYPE_ID: c_int = ffi::LUA_TFUNCTION;
}
/// Future for asynchronous function calls.
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct AsyncCallFuture<R: FromLuaMulti>(Result<AsyncThread<R>>);
+7 -10
View File
@@ -66,7 +66,6 @@
// warnings at all.
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(not(send), allow(clippy::arc_with_non_send_sync))]
#![allow(clippy::ptr_eq)]
#![allow(unsafe_op_in_unsafe_fn)]
#[macro_use]
@@ -75,9 +74,7 @@ mod macros;
mod buffer;
mod chunk;
mod conversion;
mod debug;
mod error;
mod function;
#[cfg(any(feature = "luau", doc))]
mod luau;
mod memory;
@@ -86,7 +83,6 @@ mod scope;
mod state;
mod stdlib;
mod string;
mod table;
mod thread;
mod traits;
mod types;
@@ -95,21 +91,23 @@ mod util;
mod value;
mod vector;
pub mod debug;
pub mod function;
pub mod prelude;
pub mod table;
pub use bstr::BString;
pub use ffi::{self, lua_CFunction, lua_State};
pub use crate::chunk::{AsChunk, Chunk, ChunkMode};
pub use crate::debug::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack};
pub use crate::error::{Error, ErrorContext, ExternalError, ExternalResult, Result};
pub use crate::function::{Function, FunctionInfo};
pub use crate::function::Function;
pub use crate::multi::{MultiValue, Variadic};
pub use crate::scope::Scope;
pub use crate::state::{GCMode, Lua, LuaOptions, WeakLua};
pub use crate::stdlib::StdLib;
pub use crate::string::{BorrowedBytes, BorrowedStr, String};
pub use crate::table::{Table, TablePairs, TableSequence};
pub use crate::string::{BorrowedBytes, BorrowedStr, LuaString, LuaString as String};
pub use crate::table::Table;
pub use crate::thread::{Thread, ThreadStatus};
pub use crate::traits::{
FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, LuaNativeFn, LuaNativeFnMut, ObjectLike,
@@ -131,7 +129,6 @@ pub use crate::debug::HookTriggers;
pub use crate::{
buffer::Buffer,
chunk::{CompileConstant, Compiler},
function::CoverageInfo,
luau::{HeapDump, NavigateError, Require, TextRequirer},
vector::Vector,
};
@@ -143,7 +140,7 @@ pub use crate::{thread::AsyncThread, traits::LuaNativeAsyncFn};
#[cfg(feature = "serde")]
#[doc(inline)]
pub use crate::{
serde::{de::Options as DeserializeOptions, ser::Options as SerializeOptions, LuaSerdeExt},
serde::{LuaSerdeExt, de::Options as DeserializeOptions, ser::Options as SerializeOptions},
value::SerializableValue,
};
+13 -13
View File
@@ -79,10 +79,10 @@ impl HeapDump {
let mut size_by_type = HashMap::new();
let objects = self.data["objects"].as_object()?;
for obj in objects.values() {
if let Some(cat_id) = category_id {
if obj["cat"].as_i64()? != cat_id {
continue;
}
if let Some(cat_id) = category_id
&& obj["cat"].as_i64()? != cat_id
{
continue;
}
update_size(&mut size_by_type, obj["type"].as_str()?, obj["size"].as_u64()?);
}
@@ -123,18 +123,18 @@ impl HeapDump {
if obj["type"] != "userdata" {
continue;
}
if let Some(cat_id) = category_id {
if obj["cat"].as_i64()? != cat_id {
continue;
}
if let Some(cat_id) = category_id
&& obj["cat"].as_i64()? != cat_id
{
continue;
}
// Determine userdata type from metatable
let mut ud_type = "unknown";
if let Some(metatable_addr) = obj["metatable"].as_str() {
if let Some(t) = get_key(objects, &objects[metatable_addr], "__type") {
ud_type = t;
}
if let Some(metatable_addr) = obj["metatable"].as_str()
&& let Some(t) = get_key(objects, &objects[metatable_addr], "__type")
{
ud_type = t;
}
update_size(&mut size_by_userdata, ud_type, obj["size"].as_u64()?);
}
@@ -155,7 +155,7 @@ impl HeapDump {
/// Updates the size mapping for a given key.
fn update_size<K: Eq + Hash>(size_type: &mut HashMap<K, (usize, u64)>, key: K, size: u64) {
let (ref mut count, ref mut total_size) = size_type.entry(key).or_insert((0, 0));
let (count, total_size) = size_type.entry(key).or_insert((0, 0));
*count += 1;
*total_size += size;
}
+1 -1
View File
@@ -5,7 +5,7 @@ use std::ptr;
use crate::chunk::ChunkMode;
use crate::error::{Error, Result};
use crate::function::Function;
use crate::state::{callback_error_ext, ExtraData, Lua};
use crate::state::{ExtraData, Lua, callback_error_ext};
use crate::traits::{FromLuaMulti, IntoLua};
use crate::types::MaybeSend;
+1 -1
View File
@@ -8,7 +8,7 @@ use std::{fmt, mem, ptr};
use crate::error::{Error, Result};
use crate::function::Function;
use crate::state::{callback_error_ext, Lua};
use crate::state::{Lua, callback_error_ext};
use crate::table::Table;
use crate::types::MaybeSend;
+4 -4
View File
@@ -42,10 +42,10 @@ impl TextRequirer {
}
fn normalize_chunk_name(chunk_name: &str) -> &str {
if let Some((path, line)) = chunk_name.rsplit_once(':') {
if line.parse::<u32>().is_ok() {
return path;
}
if let Some((path, line)) = chunk_name.rsplit_once(':')
&& line.parse::<u32>().is_ok()
{
return path;
}
chunk_name
}
-13
View File
@@ -28,9 +28,7 @@ impl MemoryState {
}
#[cfg(not(feature = "luau"))]
#[rustversion::since(1.85)]
#[inline]
#[allow(clippy::incompatible_msrv)]
pub(crate) unsafe fn get(state: *mut ffi::lua_State) -> *mut Self {
let mut mem_state = ptr::null_mut();
if !ptr::fn_addr_eq(ffi::lua_getallocf(state, &mut mem_state), ALLOCATOR) {
@@ -39,17 +37,6 @@ impl MemoryState {
mem_state as *mut MemoryState
}
#[cfg(not(feature = "luau"))]
#[rustversion::before(1.85)]
#[inline]
pub(crate) unsafe fn get(state: *mut ffi::lua_State) -> *mut Self {
let mut mem_state = ptr::null_mut();
if ffi::lua_getallocf(state, &mut mem_state) != ALLOCATOR {
mem_state = ptr::null_mut();
}
mem_state as *mut MemoryState
}
#[inline]
pub(crate) fn used_memory(&self) -> usize {
self.used_memory as usize
+1 -1
View File
@@ -1,4 +1,4 @@
use std::collections::{vec_deque, VecDeque};
use std::collections::{VecDeque, vec_deque};
use std::iter::FromIterator;
use std::mem;
use std::ops::{Deref, DerefMut};
+7 -8
View File
@@ -5,16 +5,16 @@ pub use crate::{
AnyUserData as LuaAnyUserData, BorrowedBytes as LuaBorrowedBytes, BorrowedStr as LuaBorrowedStr,
Chunk as LuaChunk, Either as LuaEither, Error as LuaError, ErrorContext as LuaErrorContext,
ExternalError as LuaExternalError, ExternalResult as LuaExternalResult, FromLua, FromLuaMulti,
Function as LuaFunction, FunctionInfo as LuaFunctionInfo, GCMode as LuaGCMode, Integer as LuaInteger,
IntoLua, IntoLuaMulti, LightUserData as LuaLightUserData, Lua, LuaNativeFn, LuaNativeFnMut, LuaOptions,
Function as LuaFunction, GCMode as LuaGCMode, Integer as LuaInteger, IntoLua, IntoLuaMulti,
LightUserData as LuaLightUserData, Lua, LuaNativeFn, LuaNativeFnMut, LuaOptions, LuaString,
MetaMethod as LuaMetaMethod, MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber,
ObjectLike as LuaObjectLike, RegistryKey as LuaRegistryKey, Result as LuaResult, StdLib as LuaStdLib,
String as LuaString, Table as LuaTable, TablePairs as LuaTablePairs, TableSequence as LuaTableSequence,
Thread as LuaThread, ThreadStatus as LuaThreadStatus, UserData as LuaUserData,
Table as LuaTable, Thread as LuaThread, ThreadStatus as LuaThreadStatus, UserData as LuaUserData,
UserDataFields as LuaUserDataFields, UserDataMetatable as LuaUserDataMetatable,
UserDataMethods as LuaUserDataMethods, UserDataRef as LuaUserDataRef,
UserDataRefMut as LuaUserDataRefMut, UserDataRegistry as LuaUserDataRegistry, Value as LuaValue,
Variadic as LuaVariadic, VmState as LuaVmState, WeakLua,
Variadic as LuaVariadic, VmState as LuaVmState, WeakLua, function::FunctionInfo as LuaFunctionInfo,
table::TablePairs as LuaTablePairs, table::TableSequence as LuaTableSequence,
};
#[cfg(not(feature = "luau"))]
@@ -24,9 +24,8 @@ pub use crate::HookTriggers as LuaHookTriggers;
#[cfg(feature = "luau")]
#[doc(no_inline)]
pub use crate::{
CompileConstant as LuaCompileConstant, CoverageInfo as LuaCoverageInfo,
NavigateError as LuaNavigateError, Require as LuaRequire, TextRequirer as LuaTextRequirer,
Vector as LuaVector,
CompileConstant as LuaCompileConstant, NavigateError as LuaNavigateError, Require as LuaRequire,
TextRequirer as LuaTextRequirer, Vector as LuaVector,
};
#[cfg(feature = "async")]
+1 -1
View File
@@ -8,7 +8,7 @@ use crate::state::{Lua, LuaGuard, RawLua};
use crate::traits::{FromLuaMulti, IntoLuaMulti};
use crate::types::{Callback, CallbackUpvalue, ScopedCallback, ValueRef};
use crate::userdata::{AnyUserData, UserData, UserDataRegistry, UserDataStorage};
use crate::util::{self, check_stack, get_metatable_ptr, get_userdata, take_userdata, StackGuard};
use crate::util::{self, StackGuard, check_stack, get_metatable_ptr, get_userdata, take_userdata};
/// Constructed by the [`Lua::scope`] method, allows temporarily creating Lua userdata and
/// callbacks that are not required to be `Send` or `'static`.
+3 -4
View File
@@ -4,7 +4,6 @@ use std::cell::RefCell;
use std::os::raw::c_void;
use std::rc::Rc;
use std::result::Result as StdResult;
use std::string::String as StdString;
use rustc_hash::FxHashSet;
use serde::de::{self, IntoDeserializer};
@@ -243,14 +242,14 @@ impl<'de> serde::Deserializer<'de> for Deserializer {
Value::Table(table) => {
let _guard = RecursionGuard::new(&table, &self.visited);
let mut iter = table.pairs::<StdString, Value>();
let mut iter = table.pairs::<String, Value>();
let (variant, value) = match iter.next() {
Some(v) => v?,
None => {
return Err(de::Error::invalid_value(
de::Unexpected::Map,
&"map with a single key",
))
));
}
};
@@ -621,7 +620,7 @@ impl<'de> de::MapAccess<'de> for MapDeserializer<'_> {
}
struct EnumDeserializer {
variant: StdString,
variant: String,
value: Option<Value>,
options: Options,
visited: Rc<RefCell<FxHashSet<*const c_void>>>,
+5 -5
View File
@@ -1,6 +1,6 @@
//! Serialize a Rust data structure into Lua value.
use serde::{ser, Serialize};
use serde::{Serialize, ser};
use super::LuaSerdeExt;
use crate::error::{Error, Result};
@@ -531,10 +531,10 @@ impl ser::SerializeStruct for SerializeStruct<'_> {
Some(table @ Value::Table(_)) => Ok(table),
Some(value @ Value::String(_)) if self.options.detect_serde_json_arbitrary_precision => {
let number_s = value.to_string()?;
if number_s.contains(['.', 'e', 'E']) {
if let Ok(number) = number_s.parse().map(Value::Number) {
return Ok(number);
}
if number_s.contains(['.', 'e', 'E'])
&& let Ok(number) = number_s.parse().map(Value::Number)
{
return Ok(number);
}
Ok(number_s
.parse()
+16 -25
View File
@@ -15,7 +15,7 @@ use crate::memory::MemoryState;
use crate::multi::MultiValue;
use crate::scope::Scope;
use crate::stdlib::StdLib;
use crate::string::String;
use crate::string::LuaString;
use crate::table::Table;
use crate::thread::Thread;
use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
@@ -24,7 +24,7 @@ use crate::types::{
ReentrantMutexGuard, RegistryKey, VmState, XRc, XWeak,
};
use crate::userdata::{AnyUserData, UserData, UserDataProxy, UserDataRegistry, UserDataStorage};
use crate::util::{assert_stack, check_stack, protect_lua_closure, push_string, rawset_field, StackGuard};
use crate::util::{StackGuard, assert_stack, check_stack, protect_lua_closure, push_string, rawset_field};
use crate::value::{Nil, Value};
#[cfg(not(feature = "luau"))]
@@ -855,7 +855,6 @@ impl Lua {
{
use std::ffi::CStr;
use std::os::raw::{c_char, c_void};
use std::string::String as StdString;
unsafe extern "C-unwind" fn warn_proc(ud: *mut c_void, msg: *const c_char, tocont: c_int) {
let extra = ud as *mut ExtraData;
@@ -865,7 +864,7 @@ impl Lua {
if XRc::strong_count(&warn_callback) > 2 {
return Ok(());
}
let msg = StdString::from_utf8_lossy(CStr::from_ptr(msg).to_bytes());
let msg = String::from_utf8_lossy(CStr::from_ptr(msg).to_bytes());
warn_callback((*extra).lua(), &msg, tocont != 0)
});
}
@@ -936,7 +935,7 @@ impl Lua {
///
/// The `msg` parameter, if provided, is added at the beginning of the traceback.
/// The `level` parameter works the same way as in [`Lua::inspect_stack`].
pub fn traceback(&self, msg: Option<&str>, level: usize) -> Result<String> {
pub fn traceback(&self, msg: Option<&str>, level: usize) -> Result<LuaString> {
let lua = self.lock();
unsafe {
check_stack(lua.state(), 3)?;
@@ -948,7 +947,7 @@ impl Lua {
// `protect_lua` adds it's own call frame, so we need to increase level by 1
ffi::luaL_traceback(state, state, msg, (level + 1) as c_int);
})?;
Ok(String(lua.pop_ref()))
Ok(LuaString(lua.pop_ref()))
}
}
@@ -1127,7 +1126,7 @@ impl Lua {
#[cfg(not(feature = "luau"))]
let _ = step_size; // Ignored
return GCMode::Incremental;
GCMode::Incremental
}
#[cfg(feature = "lua55")]
@@ -1205,10 +1204,10 @@ impl Lua {
#[doc(hidden)]
#[allow(clippy::result_unit_err)]
pub fn set_fflag(name: &str, enabled: bool) -> StdResult<(), ()> {
if let Ok(name) = std::ffi::CString::new(name) {
if unsafe { ffi::luau_setfflag(name.as_ptr(), enabled as c_int) != 0 } {
return Ok(());
}
if let Ok(name) = std::ffi::CString::new(name)
&& unsafe { ffi::luau_setfflag(name.as_ptr(), enabled as c_int) != 0 }
{
return Ok(());
}
Err(())
}
@@ -1248,7 +1247,7 @@ impl Lua {
/// Lua strings can be arbitrary `[u8]` data including embedded nulls, so in addition to `&str`
/// and `&String`, you can also pass plain `&[u8]` here.
#[inline]
pub fn create_string(&self, s: impl AsRef<[u8]>) -> Result<String> {
pub fn create_string(&self, s: impl AsRef<[u8]>) -> Result<LuaString> {
unsafe { self.lock().create_string(s.as_ref()) }
}
@@ -1259,7 +1258,7 @@ impl Lua {
#[cfg(feature = "lua55")]
#[cfg_attr(docsrs, doc(cfg(feature = "lua55")))]
#[inline]
pub fn create_external_string(&self, s: impl Into<Vec<u8>>) -> Result<String> {
pub fn create_external_string(&self, s: impl Into<Vec<u8>>) -> Result<LuaString> {
unsafe { self.lock().create_external_string(s.into()) }
}
@@ -1741,7 +1740,7 @@ impl Lua {
///
/// To succeed, the value must be a string (in which case this is a no-op), an integer, or a
/// number.
pub fn coerce_string(&self, v: Value) -> Result<Option<String>> {
pub fn coerce_string(&self, v: Value) -> Result<Option<LuaString>> {
Ok(match v {
Value::String(s) => Some(s),
v => unsafe {
@@ -1759,7 +1758,7 @@ impl Lua {
})?
};
if !res.is_null() {
Some(String(lua.pop_ref()))
Some(LuaString(lua.pop_ref()))
} else {
None
}
@@ -1785,11 +1784,7 @@ impl Lua {
lua.push_value(&v)?;
let mut isint = 0;
let i = ffi::lua_tointegerx(state, -1, &mut isint);
if isint == 0 {
None
} else {
Some(i)
}
if isint == 0 { None } else { Some(i) }
},
})
}
@@ -1811,11 +1806,7 @@ impl Lua {
lua.push_value(&v)?;
let mut isnum = 0;
let n = ffi::lua_tonumberx(state, -1, &mut isnum);
if isnum == 0 {
None
} else {
Some(n)
}
if isnum == 0 { None } else { Some(n) }
},
})
}
+1 -1
View File
@@ -14,7 +14,7 @@ use crate::state::RawLua;
use crate::stdlib::StdLib;
use crate::types::{AppData, ReentrantMutex, XRc};
use crate::userdata::RawUserDataRegistry;
use crate::util::{get_internal_metatable, push_internal_userdata, TypeKey, WrappedFailure};
use crate::util::{TypeKey, WrappedFailure, get_internal_metatable, push_internal_userdata};
#[cfg(any(feature = "luau", doc))]
use crate::chunk::Compiler;
+24 -26
View File
@@ -10,10 +10,10 @@ use std::sync::Arc;
use crate::chunk::ChunkMode;
use crate::error::{Error, Result};
use crate::function::Function;
use crate::memory::{MemoryState, ALLOCATOR};
use crate::memory::{ALLOCATOR, MemoryState};
use crate::state::util::callback_error_ext;
use crate::stdlib::StdLib;
use crate::string::String;
use crate::string::LuaString;
use crate::table::Table;
use crate::thread::Thread;
use crate::traits::IntoLua;
@@ -22,14 +22,14 @@ use crate::types::{
LuaType, MaybeSend, ReentrantMutex, RegistryKey, ValueRef, XRc,
};
use crate::userdata::{
init_userdata_metatable, AnyUserData, MetaMethod, RawUserDataRegistry, UserData, UserDataRegistry,
UserDataStorage,
AnyUserData, MetaMethod, RawUserDataRegistry, UserData, UserDataRegistry, UserDataStorage,
init_userdata_metatable,
};
use crate::util::{
assert_stack, check_stack, get_destructed_userdata_metatable, get_internal_userdata, get_main_state,
get_metatable_ptr, get_userdata, init_error_registry, init_internal_metatable, pop_error,
push_internal_userdata, push_string, push_table, push_userdata, rawset_field, safe_pcall, safe_xpcall,
short_type_name, StackGuard, WrappedFailure,
StackGuard, WrappedFailure, assert_stack, check_stack, get_destructed_userdata_metatable,
get_internal_userdata, get_main_state, get_metatable_ptr, get_userdata, init_error_registry,
init_internal_metatable, pop_error, push_internal_userdata, push_string, push_table, push_userdata,
rawset_field, safe_pcall, safe_xpcall, short_type_name,
};
use crate::value::{Nil, Value};
@@ -516,34 +516,34 @@ impl RawLua {
}
/// See [`Lua::create_string`]
pub(crate) unsafe fn create_string(&self, s: &[u8]) -> Result<String> {
pub(crate) unsafe fn create_string(&self, s: &[u8]) -> Result<LuaString> {
let state = self.state();
if self.unlikely_memory_error() {
push_string(state, s, false)?;
return Ok(String(self.pop_ref()));
return Ok(LuaString(self.pop_ref()));
}
let _sg = StackGuard::new(state);
check_stack(state, 3)?;
push_string(state, s, true)?;
Ok(String(self.pop_ref()))
Ok(LuaString(self.pop_ref()))
}
/// Creates an external string, that is, a string that uses memory not managed by Lua.
///
/// Modifies the input data to add `\0` terminator.
#[cfg(feature = "lua55")]
pub(crate) unsafe fn create_external_string(&self, bytes: Vec<u8>) -> Result<String> {
pub(crate) unsafe fn create_external_string(&self, bytes: Vec<u8>) -> Result<LuaString> {
let state = self.state();
if self.unlikely_memory_error() {
crate::util::push_external_string(state, bytes, false)?;
return Ok(String(self.pop_ref()));
return Ok(LuaString(self.pop_ref()));
}
let _sg = StackGuard::new(state);
check_stack(state, 3)?;
crate::util::push_external_string(state, bytes, true)?;
Ok(String(self.pop_ref()))
Ok(LuaString(self.pop_ref()))
}
#[cfg(feature = "luau")]
@@ -681,10 +681,10 @@ impl RawLua {
#[cfg(feature = "async")]
pub(crate) unsafe fn recycle_thread(&self, thread: &mut Thread) {
let extra = &mut *self.extra.get();
if extra.thread_pool.len() < extra.thread_pool.capacity() {
if let Some(index) = thread.0.index_count.take() {
extra.thread_pool.push(index);
}
if extra.thread_pool.len() < extra.thread_pool.capacity()
&& let Some(index) = thread.0.index_count.take()
{
extra.thread_pool.push(index);
}
}
@@ -824,7 +824,7 @@ impl RawLua {
ffi::LUA_TSTRING => {
ffi::lua_xpush(state, self.ref_thread(), idx);
Value::String(String(self.pop_ref_thread()))
Value::String(LuaString(self.pop_ref_thread()))
}
ffi::LUA_TTABLE => {
@@ -1126,7 +1126,7 @@ impl RawLua {
#[cfg(feature = "luau")]
if registry.enable_namecall {
let map: &mut rustc_hash::FxHashMap<_, crate::types::CallbackPtr> =
methods_map.get_or_insert_with(Default::default);
methods_map.get_or_insert_default();
for (k, m) in &registry.methods {
map.insert(k.as_bytes().to_vec(), &**m);
}
@@ -1219,13 +1219,11 @@ impl RawLua {
Ok(type_id) => Ok(type_id),
Err(Error::UserDataTypeMismatch) if ffi::lua_type(state, idx) != ffi::LUA_TUSERDATA => {
// Report `FromLuaConversionError` instead
// In Luau `luaL_typename` return heap-allocated string that is valid only for
// the `state` lifetime.
// `lua_typename` is used instead to get a truly static string.
let idx_type_name = CStr::from_ptr(ffi::lua_typename(state, ffi::lua_type(state, idx)));
let idx_type_name = idx_type_name.to_str().unwrap();
let type_name = CStr::from_ptr(ffi::lua_typename(state, ffi::lua_type(state, idx)))
.to_str()
.unwrap_or("unknown");
let message = format!("expected userdata of type '{}'", short_type_name::<T>());
Err(Error::from_lua_conversion(idx_type_name, "userdata", message))
Err(Error::from_lua_conversion(type_name, "userdata", message))
}
Err(err) => Err(err),
}
+2 -2
View File
@@ -1,11 +1,11 @@
use std::os::raw::c_int;
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::panic::{AssertUnwindSafe, catch_unwind};
use std::ptr;
use std::sync::Arc;
use crate::error::{Error, Result};
use crate::state::{ExtraData, RawLua};
use crate::util::{self, get_internal_metatable, WrappedFailure};
use crate::util::{self, WrappedFailure, get_internal_metatable};
struct StateGuard<'a>(&'a RawLua, *mut ffi::lua_State);
+40 -44
View File
@@ -2,7 +2,6 @@ use std::borrow::{Borrow, Cow};
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::os::raw::{c_int, c_void};
use std::string::String as StdString;
use std::{cmp, fmt, slice, str};
use crate::error::{Error, Result};
@@ -21,23 +20,23 @@ use {
///
/// Unlike Rust strings, Lua strings may not be valid UTF-8.
#[derive(Clone)]
pub struct String(pub(crate) ValueRef);
pub struct LuaString(pub(crate) ValueRef);
impl String {
impl LuaString {
/// Get a [`BorrowedStr`] if the Lua string is valid UTF-8.
///
/// # Examples
///
/// ```
/// # use mlua::{Lua, Result, String};
/// # use mlua::{Lua, LuaString, Result};
/// # fn main() -> Result<()> {
/// # let lua = Lua::new();
/// let globals = lua.globals();
///
/// let version: String = globals.get("_VERSION")?;
/// let version: LuaString = globals.get("_VERSION")?;
/// assert!(version.to_str()?.contains("Lua"));
///
/// let non_utf8: String = lua.load(r#" "test\255" "#).eval()?;
/// let non_utf8: LuaString = lua.load(r#" "test\255" "#).eval()?;
/// assert!(non_utf8.to_str().is_err());
/// # Ok(())
/// # }
@@ -47,11 +46,11 @@ impl String {
BorrowedStr::try_from(self)
}
/// Converts this string to a [`StdString`].
/// Converts this Lua string to a [`String`].
///
/// Any non-Unicode sequences are replaced with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
///
/// This method returns [`StdString`] instead of [`Cow<'_, str>`] because lifetime cannot be
/// This method returns [`String`] instead of [`Cow<'_, str>`] because lifetime cannot be
/// bound to a weak Lua object.
///
/// [U+FFFD]: std::char::REPLACEMENT_CHARACTER
@@ -70,11 +69,11 @@ impl String {
/// # }
/// ```
#[inline]
pub fn to_string_lossy(&self) -> StdString {
StdString::from_utf8_lossy(&self.as_bytes()).into_owned()
pub fn to_string_lossy(&self) -> String {
String::from_utf8_lossy(&self.as_bytes()).into_owned()
}
/// Returns an object that implements [`Display`] for safely printing a Lua [`String`] that may
/// Returns an object that implements [`Display`] for safely printing a [`LuaString`] that may
/// contain non-Unicode data.
///
/// This may perform lossy conversion.
@@ -92,10 +91,10 @@ impl String {
/// # Examples
///
/// ```
/// # use mlua::{Lua, Result, String};
/// # use mlua::{Lua, LuaString, Result};
/// # fn main() -> Result<()> {
/// # let lua = Lua::new();
/// let non_utf8: String = lua.load(r#" "test\255" "#).eval()?;
/// let non_utf8: LuaString = lua.load(r#" "test\255" "#).eval()?;
/// assert!(non_utf8.to_str().is_err()); // oh no :(
/// assert_eq!(non_utf8.as_bytes(), &b"test\xff"[..]);
/// # Ok(())
@@ -135,7 +134,7 @@ impl String {
(slice, lua)
}
/// Converts this string to a generic C pointer.
/// Converts this Lua string to a generic C pointer.
///
/// There is no way to convert the pointer back to its original value.
///
@@ -146,7 +145,7 @@ impl String {
}
}
impl fmt::Debug for String {
impl fmt::Debug for LuaString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let bytes = self.as_bytes();
// Check if the string is valid utf8
@@ -162,12 +161,12 @@ impl fmt::Debug for String {
// Lua strings are basically `&[u8]` slices, so implement `PartialEq` for anything resembling that.
//
// This makes our `String` comparable with `Vec<u8>`, `[u8]`, `&str` and `String`.
// This makes our `LuaString` comparable with `Vec<u8>`, `[u8]`, `&str` and `String`.
//
// The only downside is that this disallows a comparison with `Cow<str>`, as that only implements
// `AsRef<str>`, which collides with this impl. Requiring `AsRef<str>` would fix that, but limit us
// in other ways.
impl<T> PartialEq<T> for String
impl<T> PartialEq<T> for LuaString
where
T: AsRef<[u8]> + ?Sized,
{
@@ -176,43 +175,43 @@ where
}
}
impl PartialEq for String {
fn eq(&self, other: &String) -> bool {
impl PartialEq for LuaString {
fn eq(&self, other: &LuaString) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl Eq for String {}
impl Eq for LuaString {}
impl<T> PartialOrd<T> for String
impl<T> PartialOrd<T> for LuaString
where
T: AsRef<[u8]> + ?Sized,
{
fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
self.as_bytes().partial_cmp(&other.as_ref())
<[u8]>::partial_cmp(&self.as_bytes(), other.as_ref())
}
}
impl PartialOrd for String {
fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
impl PartialOrd for LuaString {
fn partial_cmp(&self, other: &LuaString) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for String {
fn cmp(&self, other: &String) -> cmp::Ordering {
impl Ord for LuaString {
fn cmp(&self, other: &LuaString) -> cmp::Ordering {
self.as_bytes().cmp(&other.as_bytes())
}
}
impl Hash for String {
impl Hash for LuaString {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_bytes().hash(state);
}
}
#[cfg(feature = "serde")]
impl Serialize for String {
impl Serialize for LuaString {
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
where
S: Serializer,
@@ -224,7 +223,7 @@ impl Serialize for String {
}
}
struct Display<'a>(&'a String);
struct Display<'a>(&'a LuaString);
impl fmt::Display for Display<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -237,7 +236,7 @@ impl fmt::Display for Display<'_> {
pub struct BorrowedStr<'a> {
// `buf` points to a readonly memory managed by Lua
pub(crate) buf: &'a str,
pub(crate) borrow: Cow<'a, String>,
pub(crate) borrow: Cow<'a, LuaString>,
pub(crate) _lua: Lua,
}
@@ -302,17 +301,14 @@ impl Ord for BorrowedStr<'_> {
}
}
impl<'a> TryFrom<&'a String> for BorrowedStr<'a> {
impl<'a> TryFrom<&'a LuaString> for BorrowedStr<'a> {
type Error = Error;
#[inline]
fn try_from(value: &'a String) -> Result<Self> {
fn try_from(value: &'a LuaString) -> Result<Self> {
let BorrowedBytes { buf, borrow, _lua } = BorrowedBytes::from(value);
let buf = str::from_utf8(buf).map_err(|e| Error::FromLuaConversionError {
from: "string",
to: "&str".to_string(),
message: Some(e.to_string()),
})?;
let buf =
str::from_utf8(buf).map_err(|e| Error::from_lua_conversion("string", "&str", e.to_string()))?;
Ok(Self { buf, borrow, _lua })
}
}
@@ -321,7 +317,7 @@ impl<'a> TryFrom<&'a String> for BorrowedStr<'a> {
pub struct BorrowedBytes<'a> {
// `buf` points to a readonly memory managed by Lua
pub(crate) buf: &'a [u8],
pub(crate) borrow: Cow<'a, String>,
pub(crate) borrow: Cow<'a, LuaString>,
pub(crate) _lua: Lua,
}
@@ -389,9 +385,9 @@ impl<'a> IntoIterator for &'a BorrowedBytes<'_> {
}
}
impl<'a> From<&'a String> for BorrowedBytes<'a> {
impl<'a> From<&'a LuaString> for BorrowedBytes<'a> {
#[inline]
fn from(value: &'a String) -> Self {
fn from(value: &'a LuaString) -> Self {
let (buf, _lua) = unsafe { value.to_slice() };
let borrow = Cow::Borrowed(value);
Self { buf, borrow, _lua }
@@ -400,7 +396,7 @@ impl<'a> From<&'a String> for BorrowedBytes<'a> {
struct WrappedString<T: AsRef<[u8]>>(T);
impl String {
impl LuaString {
/// Wraps bytes, returning an opaque type that implements [`IntoLua`] trait.
///
/// This function uses [`Lua::create_string`] under the hood.
@@ -415,7 +411,7 @@ impl<T: AsRef<[u8]>> IntoLua for WrappedString<T> {
}
}
impl LuaType for String {
impl LuaType for LuaString {
const TYPE_ID: c_int = ffi::LUA_TSTRING;
}
@@ -424,9 +420,9 @@ mod assertions {
use super::*;
#[cfg(not(feature = "send"))]
static_assertions::assert_not_impl_any!(String: Send);
static_assertions::assert_not_impl_any!(LuaString: Send);
#[cfg(feature = "send")]
static_assertions::assert_impl_all!(String: Send, Sync);
static_assertions::assert_impl_all!(LuaString: Send, Sync);
#[cfg(feature = "send")]
static_assertions::assert_impl_all!(BorrowedBytes: Send, Sync);
#[cfg(feature = "send")]
+172 -14
View File
@@ -1,15 +1,173 @@
//! Lua table handling.
//!
//! Tables are Lua's primary data structure, used for arrays, dictionaries, objects, modules,
//! and more. This module provides types for creating and manipulating Lua tables from Rust.
//!
//! # Main Types
//!
//! - [`Table`] - A handle to a Lua table.
//! - [`TablePairs`] - An iterator over key-value pairs in a table.
//! - [`TableSequence`] - An iterator over the array (sequence) portion of a table.
//!
//! # Basic Operations
//!
//! Tables support key-value access similar to Rust's `HashMap`:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//! let table = lua.create_table()?;
//!
//! // Set and get values
//! table.set("key", "value")?;
//! let value: String = table.get("key")?;
//! assert_eq!(value, "value");
//!
//! // Keys and values can be any Lua-compatible type
//! table.set(1, "first")?;
//! table.set("nested", lua.create_table()?)?;
//! # Ok(())
//! # }
//! ```
//!
//! # Array Operations
//!
//! Tables can be used as arrays with 1-based indexing:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//! let array = lua.create_table()?;
//!
//! // Push values to the end (like Vec::push)
//! array.push("first")?;
//! array.push("second")?;
//! array.push("third")?;
//!
//! // Pop from the end
//! let last: String = array.pop()?;
//! assert_eq!(last, "third");
//!
//! // Get length
//! assert_eq!(array.raw_len(), 2);
//! # Ok(())
//! # }
//! ```
//!
//! # Iteration
//!
//! Iterate over all key-value pairs with [`Table::pairs`]:
//!
//! ```
//! # use mlua::{Lua, Result, Value};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//! let table = lua.create_table()?;
//! table.set("a", 1)?;
//! table.set("b", 2)?;
//!
//! for pair in table.pairs::<String, i32>() {
//! let (key, value) = pair?;
//! println!("{key} = {value}");
//! }
//! # Ok(())
//! # }
//! ```
//!
//! For array portions, use [`Table::sequence_values`]:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//! let array = lua.create_sequence_from(["a", "b", "c"])?;
//!
//! for value in array.sequence_values::<String>() {
//! println!("{}", value?);
//! }
//! # Ok(())
//! # }
//! ```
//!
//! # Raw vs Normal Access
//!
//! Methods prefixed with `raw_` (like [`Table::raw_get`], [`Table::raw_set`]) bypass
//! metamethods, directly accessing the table's contents. Normal methods may trigger
//! `__index`, `__newindex`, and other metamethods:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//!
//! // raw_set bypasses __newindex metamethod
//! let t = lua.create_table()?;
//! t.raw_set("key", "value")?;
//!
//! // raw_get bypasses __index metamethod
//! let v: String = t.raw_get("key")?;
//! # Ok(())
//! # }
//! ```
//!
//! # Metatables
//!
//! Tables can have metatables that customize their behavior:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//!
//! let table = lua.create_table()?;
//! let metatable = lua.create_table()?;
//!
//! // Set a default value via __index
//! metatable.set("__index", lua.create_function(|_, _: ()| Ok("default"))?)?;
//! table.set_metatable(Some(metatable))?;
//!
//! // Accessing missing keys returns "default"
//! let value: String = table.get("missing")?;
//! assert_eq!(value, "default");
//! # Ok(())
//! # }
//! ```
//!
//! # Global Table
//!
//! The Lua global environment is itself a table, accessible via [`Lua::globals`]:
//!
//! ```
//! # use mlua::{Lua, Result};
//! # fn main() -> Result<()> {
//! let lua = Lua::new();
//! let globals = lua.globals();
//!
//! // Set a global variable
//! globals.set("my_var", 42)?;
//!
//! // Now accessible from Lua code
//! let result: i32 = lua.load("my_var + 8").eval()?;
//! assert_eq!(result, 50);
//! # Ok(())
//! # }
//! ```
//!
//! [`Lua::globals`]: crate::Lua::globals
use std::collections::HashSet;
use std::fmt;
use std::marker::PhantomData;
use std::os::raw::c_void;
use std::string::String as StdString;
use crate::error::{Error, Result};
use crate::function::Function;
use crate::state::{LuaGuard, RawLua, WeakLua};
use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, ObjectLike};
use crate::types::{Integer, ValueRef};
use crate::util::{assert_stack, check_stack, get_metatable_ptr, StackGuard};
use crate::util::{StackGuard, assert_stack, check_stack, get_metatable_ptr};
use crate::value::{Nil, Value};
#[cfg(feature = "async")]
@@ -226,15 +384,15 @@ impl Table {
// Compare using `__eq` metamethod if exists
// First, check the self for the metamethod.
// If self does not define it, then check the other table.
if let Some(mt) = self.metatable() {
if mt.contains_key("__eq")? {
return mt.get::<Function>("__eq")?.call((self, other));
}
if let Some(mt) = self.metatable()
&& let Some(eq_func) = mt.get::<Option<Function>>("__eq")?
{
return eq_func.call((self, other));
}
if let Some(mt) = other.metatable() {
if mt.contains_key("__eq")? {
return mt.get::<Function>("__eq")?.call((self, other));
}
if let Some(mt) = other.metatable()
&& let Some(eq_func) = mt.get::<Option<Function>>("__eq")?
{
return eq_func.call((self, other));
}
Ok(false)
@@ -1008,7 +1166,7 @@ impl ObjectLike for Table {
}
#[inline]
fn to_string(&self) -> Result<StdString> {
fn to_string(&self) -> Result<String> {
Value::Table(Table(self.0.clone())).to_string()
}
@@ -1070,7 +1228,7 @@ impl Serialize for SerializableTable<'_> {
where
S: Serializer,
{
use crate::serde::de::{check_value_for_skip, MapPairs, RecursionGuard};
use crate::serde::de::{MapPairs, RecursionGuard, check_value_for_skip};
use crate::value::SerializableValue;
let convert_result = |res: Result<()>, serialize_err: Option<S::Error>| match res {
@@ -1098,7 +1256,7 @@ impl Serialize for SerializableTable<'_> {
seq.serialize_element(&SerializableValue::new(&value, options, Some(visited)))
.map_err(|err| {
serialize_err = Some(err);
Error::SerializeError(StdString::new())
Error::SerializeError(String::new())
})
});
convert_result(res, serialize_err)?;
@@ -1123,7 +1281,7 @@ impl Serialize for SerializableTable<'_> {
)
.map_err(|err| {
serialize_err = Some(err);
Error::SerializeError(StdString::new())
Error::SerializeError(String::new())
})
};
+2 -1
View File
@@ -6,7 +6,7 @@ use crate::function::Function;
use crate::state::RawLua;
use crate::traits::{FromLuaMulti, IntoLuaMulti};
use crate::types::{LuaType, ValueRef};
use crate::util::{check_stack, error_traceback_thread, pop_error, StackGuard};
use crate::util::{StackGuard, check_stack, error_traceback_thread, pop_error};
#[cfg(not(feature = "luau"))]
use crate::{
@@ -523,6 +523,7 @@ impl<R> AsyncThread<R> {
#[cfg(feature = "async")]
impl<R> Drop for AsyncThread<R> {
fn drop(&mut self) {
#[allow(clippy::collapsible_if)]
if self.recycle {
if let Some(lua) = self.thread.0.lua.try_lock() {
unsafe {
+2 -3
View File
@@ -1,5 +1,4 @@
use std::os::raw::c_int;
use std::string::String as StdString;
use std::sync::Arc;
use crate::error::{Error, Result};
@@ -236,7 +235,7 @@ pub trait ObjectLike: Sealed {
/// Converts the object to a string in a human-readable format.
///
/// This might invoke the `__tostring` metamethod.
fn to_string(&self) -> Result<StdString>;
fn to_string(&self) -> Result<String>;
/// Converts the object to a Lua value.
fn to_value(&self) -> Value;
@@ -339,7 +338,7 @@ impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
pub(crate) trait ShortTypeName {
#[inline(always)]
fn type_name() -> StdString {
fn type_name() -> String {
short_type_name::<Self>()
}
}
+1 -1
View File
@@ -69,7 +69,7 @@ mod inner {
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0 .0
&self.0.0
}
}
}
+4 -4
View File
@@ -55,10 +55,10 @@ impl Drop for ValueRef {
if let Some(ValueRefIndex(index)) = self.index_count.take() {
// It's guaranteed that the inner value returns exactly once.
// This means in particular that the value is not dropped.
if XRc::into_inner(index).is_some() {
if let Some(lua) = self.lua.try_lock() {
unsafe { lua.drop_ref(self) };
}
if XRc::into_inner(index).is_some()
&& let Some(lua) = self.lua.try_lock()
{
unsafe { lua.drop_ref(self) }
}
}
}
+33 -34
View File
@@ -3,16 +3,15 @@ use std::ffi::CStr;
use std::fmt;
use std::hash::Hash;
use std::os::raw::{c_char, c_void};
use std::string::String as StdString;
use crate::error::{Error, Result};
use crate::function::Function;
use crate::state::Lua;
use crate::string::String;
use crate::string::LuaString;
use crate::table::{Table, TablePairs};
use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
use crate::types::{MaybeSend, ValueRef};
use crate::util::{check_stack, get_userdata, push_string, short_type_name, take_userdata, StackGuard};
use crate::util::{StackGuard, check_stack, get_userdata, push_string, short_type_name, take_userdata};
use crate::value::Value;
#[cfg(feature = "async")]
@@ -30,8 +29,8 @@ pub use r#ref::{UserDataRef, UserDataRefMut};
pub use registry::UserDataRegistry;
pub(crate) use registry::{RawUserDataRegistry, UserDataProxy};
pub(crate) use util::{
borrow_userdata_scoped, borrow_userdata_scoped_mut, collect_userdata, init_userdata_metatable,
TypeIdHints,
TypeIdHints, borrow_userdata_scoped, borrow_userdata_scoped_mut, collect_userdata,
init_userdata_metatable,
};
/// Kinds of metamethods that can be overridden.
@@ -185,7 +184,7 @@ impl PartialEq<MetaMethod> for &str {
}
}
impl PartialEq<MetaMethod> for StdString {
impl PartialEq<MetaMethod> for String {
fn eq(&self, other: &MetaMethod) -> bool {
self == other.name()
}
@@ -279,7 +278,7 @@ impl AsRef<str> for MetaMethod {
}
}
impl From<MetaMethod> for StdString {
impl From<MetaMethod> for String {
#[inline]
fn from(method: MetaMethod) -> Self {
method.name().to_owned()
@@ -295,7 +294,7 @@ pub trait UserDataMethods<T> {
///
/// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will
/// be used as a fall-back if no regular method is found.
fn add_method<M, A, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_method<M, A, R>(&mut self, name: impl Into<String>, method: M)
where
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -306,7 +305,7 @@ pub trait UserDataMethods<T> {
/// Refer to [`add_method`] for more information about the implementation.
///
/// [`add_method`]: UserDataMethods::add_method
fn add_method_mut<M, A, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_method_mut<M, A, R>(&mut self, name: impl Into<String>, method: M)
where
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -320,7 +319,7 @@ pub trait UserDataMethods<T> {
/// The method can be called only once per userdata instance, subsequent calls will result in a
/// [`Error::UserDataDestructed`] error.
#[doc(hidden)]
fn add_method_once<M, A, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_method_once<M, A, R>(&mut self, name: impl Into<String>, method: M)
where
T: 'static,
M: Fn(&Lua, T, A) -> Result<R> + MaybeSend + 'static,
@@ -342,7 +341,7 @@ pub trait UserDataMethods<T> {
/// [`add_method`]: UserDataMethods::add_method
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_method<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_async_method<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where
T: 'static,
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
@@ -357,7 +356,7 @@ pub trait UserDataMethods<T> {
/// [`add_method`]: UserDataMethods::add_method
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where
T: 'static,
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
@@ -375,7 +374,7 @@ pub trait UserDataMethods<T> {
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
#[doc(hidden)]
fn add_async_method_once<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_async_method_once<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where
T: 'static,
M: Fn(Lua, T, A) -> MR + MaybeSend + 'static,
@@ -398,7 +397,7 @@ pub trait UserDataMethods<T> {
/// The first argument will be a [`AnyUserData`] of type `T` if the method is called with Lua
/// method syntax: `my_userdata:my_method(arg1, arg2)`, or it is passed in as the first
/// argument: `my_userdata.my_method(my_userdata, arg1, arg2)`.
fn add_function<F, A, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_function<F, A, R>(&mut self, name: impl Into<String>, function: F)
where
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -409,7 +408,7 @@ pub trait UserDataMethods<T> {
/// This is a version of [`add_function`] that accepts a `FnMut` argument.
///
/// [`add_function`]: UserDataMethods::add_function
fn add_function_mut<F, A, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_function_mut<F, A, R>(&mut self, name: impl Into<String>, function: F)
where
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -423,7 +422,7 @@ pub trait UserDataMethods<T> {
/// [`add_function`]: UserDataMethods::add_function
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_function<F, A, FR, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_async_function<F, A, FR, R>(&mut self, name: impl Into<String>, function: F)
where
F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
@@ -438,7 +437,7 @@ pub trait UserDataMethods<T> {
/// side has a metatable. To prevent this, use [`add_meta_function`].
///
/// [`add_meta_function`]: UserDataMethods::add_meta_function
fn add_meta_method<M, A, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_meta_method<M, A, R>(&mut self, name: impl Into<String>, method: M)
where
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -452,7 +451,7 @@ pub trait UserDataMethods<T> {
/// side has a metatable. To prevent this, use [`add_meta_function`].
///
/// [`add_meta_function`]: UserDataMethods::add_meta_function
fn add_meta_method_mut<M, A, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_meta_method_mut<M, A, R>(&mut self, name: impl Into<String>, method: M)
where
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -468,7 +467,7 @@ pub trait UserDataMethods<T> {
docsrs,
doc(cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau")))))
)]
fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where
T: 'static,
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
@@ -484,7 +483,7 @@ pub trait UserDataMethods<T> {
/// [`add_meta_method_mut`]: UserDataMethods::add_meta_method_mut
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where
T: 'static,
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
@@ -497,7 +496,7 @@ pub trait UserDataMethods<T> {
/// Metamethods for binary operators can be triggered if either the left or right argument to
/// the binary operator has a metatable, so the first argument here is not necessarily a
/// userdata of type `T`.
fn add_meta_function<F, A, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_meta_function<F, A, R>(&mut self, name: impl Into<String>, function: F)
where
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -508,7 +507,7 @@ pub trait UserDataMethods<T> {
/// This is a version of [`add_meta_function`] that accepts a `FnMut` argument.
///
/// [`add_meta_function`]: UserDataMethods::add_meta_function
fn add_meta_function_mut<F, A, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_meta_function_mut<F, A, R>(&mut self, name: impl Into<String>, function: F)
where
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -524,7 +523,7 @@ pub trait UserDataMethods<T> {
docsrs,
doc(cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau")))))
)]
fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl Into<String>, function: F)
where
F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
@@ -543,7 +542,7 @@ pub trait UserDataFields<T> {
///
/// If `add_meta_method` is used to set the `__index` metamethod, it will
/// be used as a fall-back if no regular field or method are found.
fn add_field<V>(&mut self, name: impl Into<StdString>, value: V)
fn add_field<V>(&mut self, name: impl Into<String>, value: V)
where
V: IntoLua + 'static;
@@ -554,7 +553,7 @@ pub trait UserDataFields<T> {
///
/// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will
/// be used as a fall-back if no regular field or method are found.
fn add_field_method_get<M, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_field_method_get<M, R>(&mut self, name: impl Into<String>, method: M)
where
M: Fn(&Lua, &T) -> Result<R> + MaybeSend + 'static,
R: IntoLua;
@@ -567,21 +566,21 @@ pub trait UserDataFields<T> {
///
/// If `add_meta_method` is used to set the `__newindex` metamethod, the `__newindex` metamethod
/// will be used as a fall-back if no regular field is found.
fn add_field_method_set<M, A>(&mut self, name: impl Into<StdString>, method: M)
fn add_field_method_set<M, A>(&mut self, name: impl Into<String>, method: M)
where
M: FnMut(&Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
A: FromLua;
/// Add a regular field getter as a function which accepts a generic [`AnyUserData`] of type `T`
/// argument.
fn add_field_function_get<F, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_field_function_get<F, R>(&mut self, name: impl Into<String>, function: F)
where
F: Fn(&Lua, AnyUserData) -> Result<R> + MaybeSend + 'static,
R: IntoLua;
/// Add a regular field setter as a function which accepts a generic [`AnyUserData`] of type `T`
/// first argument.
fn add_field_function_set<F, A>(&mut self, name: impl Into<StdString>, function: F)
fn add_field_function_set<F, A>(&mut self, name: impl Into<String>, function: F)
where
F: FnMut(&Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static,
A: FromLua;
@@ -594,7 +593,7 @@ pub trait UserDataFields<T> {
///
/// `mlua` will trigger an error on an attempt to define a protected metamethod,
/// like `__gc` or `__metatable`.
fn add_meta_field<V>(&mut self, name: impl Into<StdString>, value: V)
fn add_meta_field<V>(&mut self, name: impl Into<String>, value: V)
where
V: IntoLua + 'static;
@@ -606,7 +605,7 @@ pub trait UserDataFields<T> {
///
/// `mlua` will trigger an error on an attempt to define a protected metamethod,
/// like `__gc` or `__metatable`.
fn add_meta_field_with<F, R>(&mut self, name: impl Into<StdString>, f: F)
fn add_meta_field_with<F, R>(&mut self, name: impl Into<String>, f: F)
where
F: FnOnce(&Lua) -> Result<R> + 'static,
R: IntoLua;
@@ -1022,7 +1021,7 @@ impl AnyUserData {
/// Returns a type name of this userdata (from a metatable field).
///
/// If no type name is set, returns `None`.
pub fn type_name(&self) -> Result<Option<StdString>> {
pub fn type_name(&self) -> Result<Option<String>> {
let lua = self.0.lua.lock();
let state = lua.state();
unsafe {
@@ -1039,7 +1038,7 @@ impl AnyUserData {
ffi::luaL_getmetafield(state, -1, MetaMethod::Type.as_cstr().as_ptr())
};
match name_type {
ffi::LUA_TSTRING => Ok(Some(String(lua.pop_ref()).to_str()?.to_owned())),
ffi::LUA_TSTRING => Ok(Some(LuaString(lua.pop_ref()).to_str()?.to_owned())),
_ => Ok(None),
}
}
@@ -1126,13 +1125,13 @@ impl UserDataMetatable {
/// It skips restricted metamethods, such as `__gc` or `__metatable`.
///
/// This struct is created by the [`UserDataMetatable::pairs`] method.
pub struct UserDataMetatablePairs<'a, V>(TablePairs<'a, StdString, V>);
pub struct UserDataMetatablePairs<'a, V>(TablePairs<'a, String, V>);
impl<V> Iterator for UserDataMetatablePairs<'_, V>
where
V: FromLua,
{
type Item = Result<(StdString, V)>;
type Item = Result<(String, V)>;
fn next(&mut self) -> Option<Self::Item> {
loop {
+4 -4
View File
@@ -173,10 +173,10 @@ pub(crate) enum ScopedUserDataVariant<T> {
impl<T> Drop for ScopedUserDataVariant<T> {
#[inline]
fn drop(&mut self) {
if let Self::Boxed(value) = self {
if let Ok(value) = value.try_borrow_mut() {
unsafe { drop(Box::from_raw(*value)) };
}
if let Self::Boxed(value) = self
&& let Ok(value) = value.try_borrow_mut()
{
unsafe { drop(Box::from_raw(*value)) }
}
}
}
+2 -4
View File
@@ -1,12 +1,10 @@
use std::string::String as StdString;
use crate::Function;
use crate::error::{Error, Result};
use crate::state::WeakLua;
use crate::table::Table;
use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, ObjectLike};
use crate::userdata::AnyUserData;
use crate::value::Value;
use crate::Function;
#[cfg(feature = "async")]
use crate::function::AsyncCallFuture;
@@ -88,7 +86,7 @@ impl ObjectLike for AnyUserData {
}
#[inline]
fn to_string(&self) -> Result<StdString> {
fn to_string(&self) -> Result<String> {
Value::UserData(self.clone()).to_string()
}
+6 -6
View File
@@ -1,4 +1,4 @@
use std::any::{type_name, TypeId};
use std::any::{TypeId, type_name};
use std::ops::{Deref, DerefMut};
use std::os::raw::c_int;
use std::{fmt, mem};
@@ -446,11 +446,11 @@ impl<T> DerefMut for UserDataRefMutInner<T> {
fn try_value_to_userdata<T>(value: Value) -> Result<AnyUserData> {
match value {
Value::UserData(ud) => Ok(ud),
_ => Err(Error::FromLuaConversionError {
from: value.type_name(),
to: "userdata".to_string(),
message: Some(format!("expected userdata of type {}", type_name::<T>())),
}),
_ => Err(Error::from_lua_conversion(
value.type_name(),
"userdata",
format!("expected userdata of type {}", type_name::<T>()),
)),
}
}
+26 -27
View File
@@ -4,15 +4,14 @@ use std::any::TypeId;
use std::cell::RefCell;
use std::marker::PhantomData;
use std::os::raw::c_void;
use std::string::String as StdString;
use crate::error::{Error, Result};
use crate::state::{Lua, LuaGuard};
use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti};
use crate::types::{Callback, MaybeSend};
use crate::userdata::{
borrow_userdata_scoped, borrow_userdata_scoped_mut, AnyUserData, MetaMethod, TypeIdHints, UserData,
UserDataFields, UserDataMethods, UserDataStorage,
AnyUserData, MetaMethod, TypeIdHints, UserData, UserDataFields, UserDataMethods, UserDataStorage,
borrow_userdata_scoped, borrow_userdata_scoped_mut,
};
use crate::util::short_type_name;
use crate::value::Value;
@@ -55,7 +54,7 @@ pub(crate) struct RawUserDataRegistry {
pub(crate) destructor: ffi::lua_CFunction,
pub(crate) type_id: Option<TypeId>,
pub(crate) type_name: StdString,
pub(crate) type_name: String,
#[cfg(feature = "luau")]
pub(crate) enable_namecall: bool,
@@ -368,7 +367,7 @@ impl<T> UserDataRegistry<T> {
method: name.to_string(),
type_name: value.type_name(),
message: Some("expected nil, table or function".to_string()),
})
});
}
}
}
@@ -382,12 +381,12 @@ impl<T> UserDataRegistry<T> {
}
// Returns function name for the type `T`, without the module path
fn get_function_name<T>(name: &str) -> StdString {
fn get_function_name<T>(name: &str) -> String {
format!("{}.{name}", short_type_name::<T>())
}
impl<T> UserDataFields<T> for UserDataRegistry<T> {
fn add_field<V>(&mut self, name: impl Into<StdString>, value: V)
fn add_field<V>(&mut self, name: impl Into<String>, value: V)
where
V: IntoLua + 'static,
{
@@ -395,7 +394,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
self.raw.fields.push((name, value.into_lua(self.lua.lua())));
}
fn add_field_method_get<M, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_field_method_get<M, R>(&mut self, name: impl Into<String>, method: M)
where
M: Fn(&Lua, &T) -> Result<R> + MaybeSend + 'static,
R: IntoLua,
@@ -405,7 +404,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
self.raw.field_getters.push((name, callback));
}
fn add_field_method_set<M, A>(&mut self, name: impl Into<StdString>, method: M)
fn add_field_method_set<M, A>(&mut self, name: impl Into<String>, method: M)
where
M: FnMut(&Lua, &mut T, A) -> Result<()> + MaybeSend + 'static,
A: FromLua,
@@ -415,7 +414,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
self.raw.field_setters.push((name, callback));
}
fn add_field_function_get<F, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_field_function_get<F, R>(&mut self, name: impl Into<String>, function: F)
where
F: Fn(&Lua, AnyUserData) -> Result<R> + MaybeSend + 'static,
R: IntoLua,
@@ -425,7 +424,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
self.raw.field_getters.push((name, callback));
}
fn add_field_function_set<F, A>(&mut self, name: impl Into<StdString>, mut function: F)
fn add_field_function_set<F, A>(&mut self, name: impl Into<String>, mut function: F)
where
F: FnMut(&Lua, AnyUserData, A) -> Result<()> + MaybeSend + 'static,
A: FromLua,
@@ -435,7 +434,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
self.raw.field_setters.push((name, callback));
}
fn add_meta_field<V>(&mut self, name: impl Into<StdString>, value: V)
fn add_meta_field<V>(&mut self, name: impl Into<String>, value: V)
where
V: IntoLua + 'static,
{
@@ -445,7 +444,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
self.raw.meta_fields.push((name, field));
}
fn add_meta_field_with<F, R>(&mut self, name: impl Into<StdString>, f: F)
fn add_meta_field_with<F, R>(&mut self, name: impl Into<String>, f: F)
where
F: FnOnce(&Lua) -> Result<R> + 'static,
R: IntoLua,
@@ -458,7 +457,7 @@ impl<T> UserDataFields<T> for UserDataRegistry<T> {
}
impl<T> UserDataMethods<T> for UserDataRegistry<T> {
fn add_method<M, A, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_method<M, A, R>(&mut self, name: impl Into<String>, method: M)
where
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -469,7 +468,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.methods.push((name, callback));
}
fn add_method_mut<M, A, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_method_mut<M, A, R>(&mut self, name: impl Into<String>, method: M)
where
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -481,7 +480,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
}
#[cfg(feature = "async")]
fn add_async_method<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_async_method<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where
T: 'static,
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
@@ -495,7 +494,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
}
#[cfg(feature = "async")]
fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_async_method_mut<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where
T: 'static,
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
@@ -508,7 +507,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.async_methods.push((name, callback));
}
fn add_function<F, A, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_function<F, A, R>(&mut self, name: impl Into<String>, function: F)
where
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -519,7 +518,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.methods.push((name, callback));
}
fn add_function_mut<F, A, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_function_mut<F, A, R>(&mut self, name: impl Into<String>, function: F)
where
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -531,7 +530,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
}
#[cfg(feature = "async")]
fn add_async_function<F, A, FR, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_async_function<F, A, FR, R>(&mut self, name: impl Into<String>, function: F)
where
F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
@@ -543,7 +542,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.async_methods.push((name, callback));
}
fn add_meta_method<M, A, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_meta_method<M, A, R>(&mut self, name: impl Into<String>, method: M)
where
M: Fn(&Lua, &T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -554,7 +553,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.meta_methods.push((name, callback));
}
fn add_meta_method_mut<M, A, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_meta_method_mut<M, A, R>(&mut self, name: impl Into<String>, method: M)
where
M: FnMut(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -566,7 +565,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
}
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_async_meta_method<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where
T: 'static,
M: Fn(Lua, UserDataRef<T>, A) -> MR + MaybeSend + 'static,
@@ -580,7 +579,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
}
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl Into<StdString>, method: M)
fn add_async_meta_method_mut<M, A, MR, R>(&mut self, name: impl Into<String>, method: M)
where
T: 'static,
M: Fn(Lua, UserDataRefMut<T>, A) -> MR + MaybeSend + 'static,
@@ -593,7 +592,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.async_meta_methods.push((name, callback));
}
fn add_meta_function<F, A, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_meta_function<F, A, R>(&mut self, name: impl Into<String>, function: F)
where
F: Fn(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -604,7 +603,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
self.raw.meta_methods.push((name, callback));
}
fn add_meta_function_mut<F, A, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_meta_function_mut<F, A, R>(&mut self, name: impl Into<String>, function: F)
where
F: FnMut(&Lua, A) -> Result<R> + MaybeSend + 'static,
A: FromLuaMulti,
@@ -616,7 +615,7 @@ impl<T> UserDataMethods<T> for UserDataRegistry<T> {
}
#[cfg(all(feature = "async", not(any(feature = "lua51", feature = "luau"))))]
fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl Into<StdString>, function: F)
fn add_async_meta_function<F, A, FR, R>(&mut self, name: impl Into<String>, function: F)
where
F: Fn(Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
+3 -3
View File
@@ -2,15 +2,15 @@ use std::any::Any;
use std::fmt::Write as _;
use std::mem::MaybeUninit;
use std::os::raw::{c_int, c_void};
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
use std::ptr;
use std::sync::Arc;
use crate::error::{Error, Result};
use crate::memory::MemoryState;
use crate::util::{
check_stack, get_internal_userdata, init_internal_metatable, push_internal_userdata, push_string,
push_table, rawset_field, to_string, TypeKey, DESTRUCTED_USERDATA_METATABLE,
DESTRUCTED_USERDATA_METATABLE, TypeKey, check_stack, get_internal_userdata, init_internal_metatable,
push_internal_userdata, push_string, push_table, rawset_field, to_string,
};
static WRAPPED_FAILURE_TYPE_KEY: u8 = 0;
+6 -10
View File
@@ -6,16 +6,16 @@ use std::{ptr, slice, str};
use crate::error::{Error, Result};
pub(crate) use error::{
error_traceback, error_traceback_thread, init_error_registry, pop_error, protect_lua_call,
protect_lua_closure, WrappedFailure,
WrappedFailure, error_traceback, error_traceback_thread, init_error_registry, pop_error,
protect_lua_call, protect_lua_closure,
};
pub(crate) use path::parse_path as parse_lookup_path;
pub(crate) use short_names::short_type_name;
pub(crate) use types::TypeKey;
pub(crate) use userdata::{
get_destructed_userdata_metatable, get_internal_metatable, get_internal_userdata, get_userdata,
init_internal_metatable, push_internal_userdata, push_userdata, take_userdata,
DESTRUCTED_USERDATA_METATABLE,
DESTRUCTED_USERDATA_METATABLE, get_destructed_userdata_metatable, get_internal_metatable,
get_internal_userdata, get_userdata, init_internal_metatable, push_internal_userdata, push_userdata,
take_userdata,
};
#[cfg(not(feature = "luau"))]
@@ -264,11 +264,7 @@ pub(crate) unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut f
// Check the current state first
let is_main_state = ffi::lua_pushthread(state) == 1;
ffi::lua_pop(state, 1);
if is_main_state {
Some(state)
} else {
None
}
if is_main_state { Some(state) } else { None }
}
#[cfg(feature = "luau")]
Some(ffi::lua_mainthread(state))
+1 -1
View File
@@ -196,7 +196,7 @@ fn unquote_string<'a>(path: &'a str, chars: &mut Peekable<CharIndices<'a>>) -> R
#[cfg(test)]
mod tests {
use super::{parse_path, PathKey};
use super::{PathKey, parse_path};
#[test]
fn test_parse_path() {
+1 -1
View File
@@ -3,7 +3,7 @@ use std::{mem, ptr};
use crate::error::Result;
use crate::userdata::collect_userdata;
use crate::util::{check_stack, get_metatable_ptr, push_table, rawset_field, TypeKey};
use crate::util::{TypeKey, check_stack, get_metatable_ptr, push_table, rawset_field};
// Pushes the userdata and attaches a metatable with __gc method.
// Internally uses 3 stack spaces, does not call checkstack.
+15 -16
View File
@@ -1,19 +1,18 @@
use std::cmp::Ordering;
use std::collections::HashSet;
use std::os::raw::c_void;
use std::string::String as StdString;
use std::{fmt, ptr, str};
use num_traits::FromPrimitive;
use crate::error::{Error, Result};
use crate::function::Function;
use crate::string::{BorrowedStr, String};
use crate::string::{BorrowedStr, LuaString};
use crate::table::Table;
use crate::thread::Thread;
use crate::types::{Integer, LightUserData, Number, ValueRef};
use crate::userdata::AnyUserData;
use crate::util::{check_stack, StackGuard};
use crate::util::{StackGuard, check_stack};
#[cfg(feature = "serde")]
use {
@@ -50,7 +49,7 @@ pub enum Value {
/// An interned string, managed by Lua.
///
/// Unlike Rust strings, Lua strings may not be valid UTF-8.
String(String),
String(LuaString),
/// Reference to a Lua table.
Table(Table),
/// Reference to a Lua function (or closure).
@@ -129,7 +128,7 @@ impl Value {
#[inline]
pub fn to_pointer(&self) -> *const c_void {
match self {
Value::String(String(vref)) => {
Value::String(LuaString(vref)) => {
// In Lua < 5.4 (excluding Luau), string pointers are NULL
// Use alternative approach
let lua = vref.lua.lock();
@@ -151,8 +150,8 @@ impl Value {
///
/// This might invoke the `__tostring` metamethod for non-primitive types (eg. tables,
/// functions).
pub fn to_string(&self) -> Result<StdString> {
unsafe fn invoke_to_string(vref: &ValueRef) -> Result<StdString> {
pub fn to_string(&self) -> Result<String> {
unsafe fn invoke_to_string(vref: &ValueRef) -> Result<String> {
let lua = vref.lua.lock();
let state = lua.state();
let _guard = StackGuard::new(state);
@@ -162,7 +161,7 @@ impl Value {
protect_lua!(state, 1, 1, fn(state) {
ffi::luaL_tolstring(state, -1, ptr::null_mut());
})?;
Ok(String(lua.pop_ref()).to_str()?.to_string())
Ok(LuaString(lua.pop_ref()).to_str()?.to_string())
}
match self {
@@ -336,17 +335,17 @@ impl Value {
self.as_number()
}
/// Returns `true` if the value is a Lua [`String`].
/// Returns `true` if the value is a [`LuaString`].
#[inline]
pub fn is_string(&self) -> bool {
self.as_string().is_some()
}
/// Cast the value to Lua [`String`].
/// Cast the value to a [`LuaString`].
///
/// If the value is a Lua [`String`], returns it or `None` otherwise.
/// If the value is a [`LuaString`], returns it or `None` otherwise.
#[inline]
pub fn as_string(&self) -> Option<&String> {
pub fn as_string(&self) -> Option<&LuaString> {
match self {
Value::String(s) => Some(s),
_ => None,
@@ -355,7 +354,7 @@ impl Value {
/// Cast the value to [`BorrowedStr`].
///
/// If the value is a Lua [`String`], try to convert it to [`BorrowedStr`] or return `None`
/// If the value is a [`LuaString`], try to convert it to [`BorrowedStr`] or return `None`
/// otherwise.
#[deprecated(
since = "0.11.0",
@@ -366,15 +365,15 @@ impl Value {
self.as_string().and_then(|s| s.to_str().ok())
}
/// Cast the value to [`StdString`].
/// Cast the value to [`String`].
///
/// If the value is a Lua [`String`], converts it to [`StdString`] or returns `None` otherwise.
/// If the value is a [`LuaString`], converts it to [`String`] or returns `None` otherwise.
#[deprecated(
since = "0.11.0",
note = "This method does not follow Rust naming convention. Use `as_string().map(|s| s.to_string_lossy())` instead."
)]
#[inline]
pub fn as_string_lossy(&self) -> Option<StdString> {
pub fn as_string_lossy(&self) -> Option<String> {
self.as_string().map(|s| s.to_string_lossy())
}
+2 -3
View File
@@ -1,6 +1,5 @@
#![cfg(feature = "async")]
use std::string::String as StdString;
use std::sync::Arc;
use std::time::Duration;
@@ -40,7 +39,7 @@ async fn test_async_function() -> Result<()> {
async fn test_async_function_wrap() -> Result<()> {
let lua = Lua::new();
let f = Function::wrap_async(|s: StdString| async move {
let f = Function::wrap_async(|s: String| async move {
tokio::task::yield_now().await;
Ok(s)
});
@@ -68,7 +67,7 @@ async fn test_async_function_wrap() -> Result<()> {
async fn test_async_function_wrap_raw() -> Result<()> {
let lua = Lua::new();
let f = Function::wrap_raw_async(|s: StdString| async move {
let f = Function::wrap_raw_async(|s: String| async move {
tokio::task::yield_now().await;
s
});
+17 -13
View File
@@ -49,7 +49,7 @@ fn test_string_from_lua() -> Result<()> {
let lua = Lua::new();
// From stack
let f = lua.create_function(|_, s: mlua::String| Ok(s))?;
let f = lua.create_function(|_, s: mlua::LuaString| Ok(s))?;
let s = f.call::<String>("hello, world!")?;
assert_eq!(s, "hello, world!");
@@ -708,9 +708,10 @@ fn test_either_from_lua() -> Result<()> {
},
err => panic!("expected `Error::BadArgument`, got {err:?}"),
}
assert!(err
.to_string()
.starts_with("bad argument #1: error converting Lua string to Either<i32, Table>"),);
assert!(
err.to_string()
.starts_with("bad argument #1: error converting Lua string to Either<i32, Table>"),
);
}
err => panic!("expected `Error::CallbackError`, got {err:?}"),
}
@@ -736,15 +737,18 @@ fn test_char_from_lua() -> Result<()> {
assert_eq!(lua.convert::<char>("A")?, 'A');
assert_eq!(lua.convert::<char>(65)?, 'A');
assert_eq!(lua.convert::<char>(128175)?, '💯');
assert!(lua
.convert::<char>(5456324)
.is_err_and(|e| e.to_string().contains("integer out of range")));
assert!(lua
.convert::<char>("hello")
.is_err_and(|e| e.to_string().contains("expected string to have exactly one char")));
assert!(lua
.convert::<char>(HashMap::<String, String>::new())
.is_err_and(|e| e.to_string().contains("expected string or integer")));
assert!(
lua.convert::<char>(5456324)
.is_err_and(|e| e.to_string().contains("integer out of range"))
);
assert!(
lua.convert::<char>("hello")
.is_err_and(|e| e.to_string().contains("expected string to have exactly one char"))
);
assert!(
lua.convert::<char>(HashMap::<String, String>::new())
.is_err_and(|e| e.to_string().contains("expected string or integer"))
);
Ok(())
}
+6 -6
View File
@@ -1,4 +1,4 @@
use mlua::{Error, Function, Lua, Result, String, Table, Variadic};
use mlua::{Error, Function, Lua, LuaString, Result, Table, Variadic};
#[test]
fn test_function_call() -> Result<()> {
@@ -267,7 +267,7 @@ fn test_function_coverage() -> Result<()> {
assert_eq!(
report[0],
mlua::CoverageInfo {
mlua::function::CoverageInfo {
function: None,
line_defined: 1,
depth: 0,
@@ -276,7 +276,7 @@ fn test_function_coverage() -> Result<()> {
);
assert_eq!(
report[1],
mlua::CoverageInfo {
mlua::function::CoverageInfo {
function: Some("abc".into()),
line_defined: 4,
depth: 1,
@@ -285,7 +285,7 @@ fn test_function_coverage() -> Result<()> {
);
assert_eq!(
report[2],
mlua::CoverageInfo {
mlua::function::CoverageInfo {
function: None,
line_defined: 12,
depth: 1,
@@ -294,7 +294,7 @@ fn test_function_coverage() -> Result<()> {
);
assert_eq!(
report[3],
mlua::CoverageInfo {
mlua::function::CoverageInfo {
function: None,
line_defined: 13,
depth: 2,
@@ -343,7 +343,7 @@ fn test_function_deep_clone() -> Result<()> {
fn test_function_wrap() -> Result<()> {
let lua = Lua::new();
let f = Function::wrap(|s: String, n| Ok(s.to_str().unwrap().repeat(n)));
let f = Function::wrap(|s: LuaString, n| Ok(s.to_str().unwrap().repeat(n)));
lua.globals().set("f", f)?;
lua.load(r#"assert(f("hello", 2) == "hellohello")"#)
.exec()
+1 -1
View File
@@ -3,8 +3,8 @@
use std::cell::Cell;
use std::fmt::Debug;
use std::os::raw::c_void;
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicU64, Ordering};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicU64, Ordering};
use mlua::{
Compiler, Error, Function, Lua, LuaOptions, Result, StdLib, Table, ThreadStatus, Value, Vector, VmState,
+12 -6
View File
@@ -42,8 +42,10 @@ fn test_require_errors() {
// Pass non-string to require
let res = run_require(&lua, true);
assert!(res.is_err());
assert!((res.unwrap_err().to_string())
.contains("bad argument #1 to 'require' (string expected, got boolean)"));
assert!(
(res.unwrap_err().to_string())
.contains("bad argument #1 to 'require' (string expected, got boolean)")
);
// Require from loadstring
let res = lua
@@ -169,8 +171,10 @@ fn test_require_without_config() {
"./tests/luau/require/without_config/ambiguous_file_requirer",
);
assert!(res.is_err());
assert!((res.unwrap_err().to_string())
.contains("could not resolve child component \"dependency\" (ambiguous)"));
assert!(
(res.unwrap_err().to_string())
.contains("could not resolve child component \"dependency\" (ambiguous)")
);
// RequireWithDirectoryAmbiguity
let res = run_require(
@@ -178,8 +182,10 @@ fn test_require_without_config() {
"./tests/luau/require/without_config/ambiguous_directory_requirer",
);
assert!(res.is_err());
assert!((res.unwrap_err().to_string())
.contains("could not resolve child component \"dependency\" (ambiguous)"));
assert!(
(res.unwrap_err().to_string())
.contains("could not resolve child component \"dependency\" (ambiguous)")
);
// CheckCachedResult
let res = run_require(&lua, "./tests/luau/require/without_config/validate_cache").unwrap();
+4 -2
View File
@@ -1,4 +1,6 @@
use mlua::{Error, ExternalError, Integer, IntoLuaMulti, Lua, MultiValue, Result, String, Value, Variadic};
use mlua::{
Error, ExternalError, Integer, IntoLuaMulti, Lua, LuaString, MultiValue, Result, Value, Variadic,
};
#[test]
fn test_result_conversions() -> Result<()> {
@@ -81,7 +83,7 @@ fn test_multivalue_by_ref() -> Result<()> {
Value::Boolean(true),
]);
let f = lua.create_function(|_, (i, s, b): (i32, String, bool)| {
let f = lua.create_function(|_, (i, s, b): (i32, LuaString, bool)| {
assert_eq!(i, 3);
assert_eq!(s.to_str()?, "hello");
assert_eq!(b, true);
+7 -8
View File
@@ -1,10 +1,9 @@
use std::cell::Cell;
use std::rc::Rc;
use std::string::String as StdString;
use std::sync::Arc;
use mlua::{
AnyUserData, Error, Function, Lua, MetaMethod, ObjectLike, Result, String, UserData, UserDataFields,
AnyUserData, Error, Function, Lua, LuaString, MetaMethod, ObjectLike, Result, UserData, UserDataFields,
UserDataMethods, UserDataRegistry,
};
@@ -437,15 +436,15 @@ fn test_scope_userdata_ref_mut() -> Result<()> {
fn test_scope_any_userdata() -> Result<()> {
let lua = Lua::new();
fn register(reg: &mut UserDataRegistry<&mut StdString>) {
reg.add_method_mut("push", |_, this, s: String| {
fn register(reg: &mut UserDataRegistry<&mut String>) {
reg.add_method_mut("push", |_, this, s: LuaString| {
this.push_str(&s.to_str()?);
Ok(())
});
reg.add_meta_method("__tostring", |_, data, ()| Ok((*data).clone()));
}
let mut data = StdString::from("foo");
let mut data = String::from("foo");
lua.scope(|scope| {
let ud = scope.create_any_userdata(&mut data, register)?;
lua.globals().set("ud", ud)?;
@@ -527,11 +526,11 @@ fn test_scope_any_userdata_ref_mut() -> Result<()> {
fn test_scope_destructors() -> Result<()> {
let lua = Lua::new();
lua.register_userdata_type::<Arc<StdString>>(|reg| {
lua.register_userdata_type::<Arc<String>>(|reg| {
reg.add_meta_method("__tostring", |_, data, ()| Ok(data.to_string()));
})?;
let arc_str = Arc::new(StdString::from("foo"));
let arc_str = Arc::new(String::from("foo"));
let ud = lua.create_any_userdata(arc_str.clone())?;
lua.scope(|scope| {
@@ -544,7 +543,7 @@ fn test_scope_destructors() -> Result<()> {
// Try destructing the userdata while it's borrowed
let ud = lua.create_any_userdata(arc_str.clone())?;
ud.borrow_scoped::<Arc<StdString>, _>(|arc_str| {
ud.borrow_scoped::<Arc<String>, _>(|arc_str| {
assert_eq!(arc_str.as_str(), "foo");
lua.scope(|scope| {
scope.add_destructor(|| {
+2 -3
View File
@@ -2,7 +2,6 @@
use std::cell::UnsafeCell;
use std::marker::PhantomData;
use std::string::String as StdString;
use mlua::{AnyUserData, Error, Lua, ObjectLike, Result, UserData, UserDataMethods, UserDataRef};
use static_assertions::{assert_impl_all, assert_not_impl_all};
@@ -12,7 +11,7 @@ fn test_userdata_multithread_access_send_only() -> Result<()> {
let lua = Lua::new();
// This type is `Send` but not `Sync`.
struct MyUserData(StdString, PhantomData<UnsafeCell<()>>);
struct MyUserData(String, PhantomData<UnsafeCell<()>>);
assert_impl_all!(MyUserData: Send);
assert_not_impl_all!(MyUserData: Sync);
@@ -52,7 +51,7 @@ fn test_userdata_multithread_access_sync() -> Result<()> {
let lua = Lua::new();
// This type is `Send` and `Sync`.
struct MyUserData(StdString);
struct MyUserData(String);
assert_impl_all!(MyUserData: Send, Sync);
impl UserData for MyUserData {
+10 -10
View File
@@ -1,11 +1,11 @@
use std::borrow::Cow;
use std::collections::HashSet;
use mlua::{Lua, Result, String};
use mlua::{Lua, LuaString, Result};
#[test]
fn test_string_compare() {
fn with_str<F: FnOnce(String)>(s: &str, f: F) {
fn with_str<F: FnOnce(LuaString)>(s: &str, f: F) {
f(Lua::new().create_string(s).unwrap());
}
@@ -42,9 +42,9 @@ fn test_string_views() -> Result<()> {
.exec()?;
let globals = lua.globals();
let ok: String = globals.get("ok")?;
let err: String = globals.get("err")?;
let empty: String = globals.get("empty")?;
let ok: LuaString = globals.get("ok")?;
let err: LuaString = globals.get("err")?;
let empty: LuaString = globals.get("empty")?;
assert_eq!(ok.to_str()?, "null bytes are valid utf-8, wh\0 knew?");
assert_eq!(ok.to_string_lossy(), "null bytes are valid utf-8, wh\0 knew?");
@@ -74,7 +74,7 @@ fn test_string_from_bytes() -> Result<()> {
fn test_string_hash() -> Result<()> {
let lua = Lua::new();
let set: HashSet<String> = lua.load(r#"{"hello", "world", "abc", 321}"#).eval()?;
let set: HashSet<LuaString> = lua.load(r#"{"hello", "world", "abc", 321}"#).eval()?;
assert_eq!(set.len(), 4);
assert!(set.contains(&lua.create_string("hello")?));
assert!(set.contains(&lua.create_string("world")?));
@@ -133,13 +133,13 @@ fn test_string_display() -> Result<()> {
fn test_string_wrap() -> Result<()> {
let lua = Lua::new();
let s = String::wrap("hello, world");
let s = LuaString::wrap("hello, world");
lua.globals().set("s", s)?;
assert_eq!(lua.globals().get::<String>("s")?, "hello, world");
assert_eq!(lua.globals().get::<LuaString>("s")?, "hello, world");
let s2 = String::wrap("hello, world (owned)".to_string());
let s2 = LuaString::wrap("hello, world (owned)".to_string());
lua.globals().set("s2", s2)?;
assert_eq!(lua.globals().get::<String>("s2")?, "hello, world (owned)");
assert_eq!(lua.globals().get::<LuaString>("s2")?, "hello, world (owned)");
Ok(())
}
+29 -24
View File
@@ -1,14 +1,13 @@
use std::collections::HashMap;
#[cfg(not(target_arch = "wasm32"))]
use std::iter::FromIterator;
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::string::String as StdString;
use std::panic::{AssertUnwindSafe, catch_unwind};
use std::sync::Arc;
use std::{error, f32, f64, fmt};
use mlua::{
ffi, ChunkMode, Error, ExternalError, Function, Lua, LuaOptions, Nil, Result, StdLib, String, Table,
UserData, Value, Variadic,
ChunkMode, Error, ExternalError, Function, Lua, LuaOptions, Nil, Result, StdLib, Table, UserData, Value,
Variadic, ffi,
};
#[test]
@@ -155,7 +154,7 @@ fn test_replace_globals() -> Result<()> {
globals.set("foo", "bar")?;
lua.set_globals(globals.clone())?;
let val = lua.load("return foo").eval::<StdString>()?;
let val = lua.load("return foo").eval::<String>()?;
assert_eq!(val, "bar");
// Updating globals in sandboxed Lua state is not allowed
@@ -398,7 +397,7 @@ fn test_error() -> Result<()> {
fn test_panic() -> Result<()> {
fn make_lua(options: LuaOptions) -> Result<Lua> {
let lua = Lua::new_with(StdLib::ALL_SAFE, options)?;
let rust_panic_function = lua.create_function(|_, msg: Option<StdString>| -> Result<()> {
let rust_panic_function = lua.create_function(|_, msg: Option<String>| -> Result<()> {
if let Some(msg) = msg {
panic!("{}", msg)
}
@@ -496,7 +495,7 @@ fn test_panic() -> Result<()> {
.exec()
}) {
Ok(r) => panic!("no panic was detected: {:?}", r),
Err(p) => assert!(*p.downcast::<StdString>().unwrap() == "rust panic from lua"),
Err(p) => assert!(*p.downcast::<String>().unwrap() == "rust panic from lua"),
}
// Test disabling `catch_rust_panics` option / xpcall correctness
@@ -520,7 +519,7 @@ fn test_panic() -> Result<()> {
.exec()
}) {
Ok(r) => panic!("no panic was detected: {:?}", r),
Err(p) => assert!(*p.downcast::<StdString>().unwrap() == "rust panic from lua"),
Err(p) => assert!(*p.downcast::<String>().unwrap() == "rust panic from lua"),
}
Ok(())
@@ -684,10 +683,12 @@ fn test_pcall_xpcall() -> Result<()> {
))]
assert_eq!(globals.get::<std::string::String>("xpcall_error")?, "testerror");
#[cfg(feature = "lua51")]
assert!(globals
.get::<String>("xpcall_error")?
.to_str()?
.ends_with(": testerror"));
assert!(
globals
.get::<mlua::LuaString>("xpcall_error")?
.to_str()?
.ends_with(": testerror")
);
// Make sure that weird xpcall error recursion at least doesn't cause unsafety or panics.
lua.load(
@@ -1070,10 +1071,11 @@ fn test_ref_stack_exhaustion() {
Ok(())
})) {
Ok(_) => panic!("no panic was detected"),
Err(p) => assert!(p
.downcast::<StdString>()
.unwrap()
.starts_with("cannot create a Lua reference, out of auxiliary stack space")),
Err(p) => assert!(
p.downcast::<String>()
.unwrap()
.starts_with("cannot create a Lua reference, out of auxiliary stack space")
),
}
}
@@ -1218,7 +1220,11 @@ fn test_context_thread_51() -> Result<()> {
fn test_jit_version() -> Result<()> {
let lua = Lua::new();
let jit: Table = lua.globals().get("jit")?;
assert!(jit.get::<String>("version")?.to_str()?.contains("LuaJIT"));
assert!(
jit.get::<mlua::LuaString>("version")?
.to_str()?
.contains("LuaJIT")
);
Ok(())
}
@@ -1318,7 +1324,7 @@ fn test_inspect_stack() -> Result<()> {
// Not inside any function
assert!(lua.inspect_stack(0, |_| ()).is_none());
let logline = lua.create_function(|lua, msg: StdString| {
let logline = lua.create_function(|lua, msg: String| {
let r = lua
.inspect_stack(1, |debug| {
let source = debug.source().short_src;
@@ -1422,9 +1428,8 @@ fn test_traceback() -> Result<()> {
assert!(traceback.contains("stack traceback:"));
// Test traceback inside a function
let get_traceback = lua.create_function(|lua, (msg, level): (Option<StdString>, usize)| {
lua.traceback(msg.as_deref(), level)
})?;
let get_traceback = lua
.create_function(|lua, (msg, level): (Option<String>, usize)| lua.traceback(msg.as_deref(), level))?;
lua.globals().set("get_traceback", get_traceback)?;
lua.load(
@@ -1504,10 +1509,10 @@ fn test_multi_states() -> Result<()> {
#[cfg(any(feature = "lua55", feature = "lua54"))]
fn test_warnings() -> Result<()> {
let lua = Lua::new();
lua.set_app_data::<Vec<(StdString, bool)>>(Vec::new());
lua.set_app_data::<Vec<(String, bool)>>(Vec::new());
lua.set_warning_function(|lua, msg, incomplete| {
lua.app_data_mut::<Vec<(StdString, bool)>>()
lua.app_data_mut::<Vec<(String, bool)>>()
.unwrap()
.push((msg.to_string(), incomplete));
Ok(())
@@ -1521,7 +1526,7 @@ fn test_warnings() -> Result<()> {
lua.remove_warning_function();
lua.warning("one more warning", false);
let messages = lua.app_data_ref::<Vec<(StdString, bool)>>().unwrap();
let messages = lua.app_data_ref::<Vec<(String, bool)>>().unwrap();
assert_eq!(
*messages,
vec![
+1 -1
View File
@@ -1,6 +1,6 @@
use std::os::raw::c_void;
use mlua::{Function, LightUserData, Lua, Number, Result, String as LuaString, Thread};
use mlua::{Function, LightUserData, Lua, LuaString, Number, Result, Thread};
#[test]
fn test_lightuserdata() -> Result<()> {
+28 -23
View File
@@ -1,14 +1,13 @@
use std::any::TypeId;
use std::collections::HashMap;
use std::string::String as StdString;
use std::sync::Arc;
#[cfg(any(feature = "lua55", feature = "lua54"))]
use std::sync::atomic::{AtomicI64, Ordering};
use mlua::{
AnyUserData, Error, ExternalError, Function, Lua, MetaMethod, Nil, ObjectLike, Result, String, UserData,
UserDataFields, UserDataMethods, UserDataRef, UserDataRegistry, Value, Variadic,
AnyUserData, Error, ExternalError, Function, Lua, LuaString, MetaMethod, Nil, ObjectLike, Result,
UserData, UserDataFields, UserDataMethods, UserDataRef, UserDataRegistry, Value, Variadic,
};
#[test]
@@ -131,7 +130,7 @@ fn test_metamethods() -> Result<()> {
MetaMethod::Eq,
|_, (lhs, rhs): (UserDataRef<Self>, UserDataRef<Self>)| Ok(lhs.0 == rhs.0),
);
methods.add_meta_method(MetaMethod::Index, |_, data, index: String| {
methods.add_meta_method(MetaMethod::Index, |_, data, index: LuaString| {
if index.to_str()? == "inner" {
Ok(data.0)
} else {
@@ -291,8 +290,8 @@ fn test_gc_userdata() -> Result<()> {
let lua = Lua::new();
lua.globals().set("userdata", MyUserdata { id: 123 })?;
assert!(lua
.load(
assert!(
lua.load(
r#"
local tbl = setmetatable({
userdata = userdata
@@ -308,7 +307,8 @@ fn test_gc_userdata() -> Result<()> {
"#
)
.exec()
.is_err());
.is_err()
);
Ok(())
}
@@ -491,8 +491,8 @@ fn test_user_values() -> Result<()> {
ud.set_nth_user_value(1, "hello")?;
ud.set_nth_user_value(2, "world")?;
ud.set_nth_user_value(65535, 321)?;
assert_eq!(ud.nth_user_value::<String>(1)?, "hello");
assert_eq!(ud.nth_user_value::<String>(2)?, "world");
assert_eq!(ud.nth_user_value::<LuaString>(1)?, "hello");
assert_eq!(ud.nth_user_value::<LuaString>(2)?, "world");
assert_eq!(ud.nth_user_value::<Value>(3)?, Value::Nil);
assert_eq!(ud.nth_user_value::<i32>(65535)?, 321);
@@ -582,8 +582,8 @@ fn test_fields() -> Result<()> {
});
// Use userdata "uservalue" storage
fields.add_field_function_get("uval", |_, ud| ud.user_value::<Option<String>>());
fields.add_field_function_set("uval", |_, ud, s: Option<String>| ud.set_user_value(s));
fields.add_field_function_get("uval", |_, ud| ud.user_value::<Option<LuaString>>());
fields.add_field_function_set("uval", |_, ud, s: Option<LuaString>| ud.set_user_value(s));
fields.add_meta_field(MetaMethod::Index, HashMap::from([("f", 321)]));
fields.add_meta_field_with(MetaMethod::NewIndex, |lua| {
@@ -630,9 +630,11 @@ fn test_fields() -> Result<()> {
}
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_method(MetaMethod::Index, |_, _, name: StdString| match &*name {
"y" => Ok(Some(-1)),
_ => Ok(None),
methods.add_meta_method(MetaMethod::Index, |_, _, name: LuaString| {
match name.to_str()?.as_ref() {
"y" => Ok(Some(-1)),
_ => Ok(None),
}
});
}
}
@@ -659,7 +661,7 @@ fn test_metatable() -> Result<()> {
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
methods.add_function("my_type_name", |_, data: AnyUserData| {
let metatable = data.metatable()?;
metatable.get::<String>(MetaMethod::Type)
metatable.get::<LuaString>(MetaMethod::Type)
});
}
}
@@ -723,7 +725,10 @@ fn test_metatable() -> Result<()> {
let ud = lua.create_userdata(MyUserData3)?;
let metatable = ud.metatable()?;
assert_eq!(metatable.get::<String>(MetaMethod::Type)?.to_str()?, "CustomName");
assert_eq!(
metatable.get::<LuaString>(MetaMethod::Type)?.to_str()?,
"CustomName"
);
Ok(())
}
@@ -776,16 +781,16 @@ fn test_userdata_proxy() -> Result<()> {
fn test_any_userdata() -> Result<()> {
let lua = Lua::new();
lua.register_userdata_type::<StdString>(|reg| {
lua.register_userdata_type::<String>(|reg| {
reg.add_method("get", |_, this, ()| Ok(this.clone()));
reg.add_method_mut("concat", |_, this, s: String| {
reg.add_method_mut("concat", |_, this, s: LuaString| {
this.push_str(&s.to_string_lossy());
Ok(())
});
})?;
let ud = lua.create_any_userdata("hello".to_string())?;
assert_eq!(&*ud.borrow::<StdString>()?, "hello");
assert_eq!(&*ud.borrow::<String>()?, "hello");
lua.globals().set("ud", ud)?;
lua.load(
@@ -805,7 +810,7 @@ fn test_any_userdata() -> Result<()> {
fn test_any_userdata_wrap() -> Result<()> {
let lua = Lua::new();
lua.register_userdata_type::<StdString>(|reg| {
lua.register_userdata_type::<String>(|reg| {
reg.add_method("get", |_, this, ()| Ok(this.clone()));
})?;
@@ -857,7 +862,7 @@ fn test_userdata_object_like() -> Result<()> {
r => panic!("expected RuntimeError, got {r:?}"),
}
assert_eq!(ud.call::<String>(())?, "called");
assert_eq!(ud.call::<LuaString>(())?, "called");
ud.call_method::<()>("add", 2)?;
assert_eq!(ud.get::<u32>("n")?, 323);
@@ -1375,7 +1380,7 @@ fn test_userdata_namecall() -> Result<()> {
registry.add_method("method", |_, _, ()| Ok("method called"));
registry.add_field_method_get("field", |_, _| Ok("field value"));
registry.add_meta_method(MetaMethod::Index, |_, _, key: StdString| Ok(key));
registry.add_meta_method(MetaMethod::Index, |_, _, key: LuaString| Ok(key));
registry.enable_namecall();
}
@@ -1413,7 +1418,7 @@ fn test_userdata_get_path() -> Result<()> {
}
let ud = lua.create_userdata(MyUd)?;
assert_eq!(ud.get_path::<String>(".value")?, "userdata_value");
assert_eq!(ud.get_path::<LuaString>(".value")?, "userdata_value");
Ok(())
}
+8 -7
View File
@@ -1,7 +1,6 @@
use std::collections::HashMap;
use std::os::raw::c_void;
use std::ptr;
use std::string::String as StdString;
use mlua::{Error, LightUserData, Lua, MultiValue, Result, UserData, UserDataMethods, Value};
@@ -178,7 +177,7 @@ fn test_value_to_string() -> Result<()> {
assert!(thread.to_string()?.starts_with("thread:"));
assert_eq!(thread.type_name(), "thread");
lua.register_userdata_type::<StdString>(|reg| {
lua.register_userdata_type::<String>(|reg| {
reg.add_meta_method("__tostring", |_, this, ()| Ok(this.clone()));
})?;
let ud: Value = Value::UserData(lua.create_any_userdata(String::from("string userdata"))?);
@@ -213,9 +212,9 @@ fn test_value_to_string() -> Result<()> {
fn test_debug_format() -> Result<()> {
let lua = Lua::new();
lua.register_userdata_type::<HashMap<i32, StdString>>(|_| {})?;
lua.register_userdata_type::<HashMap<i32, String>>(|_| {})?;
let ud = lua
.create_any_userdata::<HashMap<i32, StdString>>(HashMap::new())
.create_any_userdata::<HashMap<i32, String>>(HashMap::new())
.map(Value::UserData)?;
assert!(format!("{ud:#?}").starts_with("HashMap<i32, String>:"));
@@ -259,9 +258,11 @@ fn test_value_conversions() -> Result<()> {
assert!(Value::Table(lua.create_table()?).is_table());
assert!(Value::Table(lua.create_table()?).as_table().is_some());
assert!(Value::Function(lua.create_function(|_, ()| Ok(())).unwrap()).is_function());
assert!(Value::Function(lua.create_function(|_, ()| Ok(())).unwrap())
.as_function()
.is_some());
assert!(
Value::Function(lua.create_function(|_, ()| Ok(())).unwrap())
.as_function()
.is_some()
);
assert!(Value::Thread(lua.create_thread(lua.load("function() end").eval()?)?).is_thread());
assert!(
Value::Thread(lua.create_thread(lua.load("function() end").eval()?)?)