mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Add Lua 5.5 external strings support
This commit is contained in:
@@ -204,7 +204,7 @@ unsafe extern "C-unwind" {
|
||||
L: *mut lua_State,
|
||||
s: *const c_char,
|
||||
len: usize,
|
||||
falloc: lua_Alloc,
|
||||
falloc: Option<lua_Alloc>,
|
||||
ud: *mut c_void,
|
||||
) -> *const c_char;
|
||||
pub fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char;
|
||||
|
||||
@@ -500,11 +500,21 @@ impl FromLua for crate::Buffer {
|
||||
impl IntoLua for StdString {
|
||||
#[inline]
|
||||
fn into_lua(self, lua: &Lua) -> Result<Value> {
|
||||
#[cfg(feature = "lua55")]
|
||||
if true {
|
||||
return Ok(Value::String(lua.create_external_string(self)?));
|
||||
}
|
||||
|
||||
Ok(Value::String(lua.create_string(self)?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> {
|
||||
#[cfg(feature = "lua55")]
|
||||
if lua.unlikely_memory_error() {
|
||||
return crate::util::push_external_string(lua.state(), self.into(), false);
|
||||
}
|
||||
|
||||
push_bytes_into_stack(self, lua)
|
||||
}
|
||||
}
|
||||
@@ -591,6 +601,11 @@ impl FromLua for Box<str> {
|
||||
impl IntoLua for CString {
|
||||
#[inline]
|
||||
fn into_lua(self, lua: &Lua) -> Result<Value> {
|
||||
#[cfg(feature = "lua55")]
|
||||
if true {
|
||||
return Ok(Value::String(lua.create_external_string(self)?));
|
||||
}
|
||||
|
||||
Ok(Value::String(lua.create_string(self.as_bytes())?))
|
||||
}
|
||||
}
|
||||
@@ -635,6 +650,11 @@ impl IntoLua for Cow<'_, CStr> {
|
||||
impl IntoLua for BString {
|
||||
#[inline]
|
||||
fn into_lua(self, lua: &Lua) -> Result<Value> {
|
||||
#[cfg(feature = "lua55")]
|
||||
if true {
|
||||
return Ok(Value::String(lua.create_external_string(self)?));
|
||||
}
|
||||
|
||||
Ok(Value::String(lua.create_string(self)?))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1219,6 +1219,17 @@ impl Lua {
|
||||
unsafe { self.lock().create_string(s.as_ref()) }
|
||||
}
|
||||
|
||||
/// Creates and returns an external Lua string.
|
||||
///
|
||||
/// External string is a string where the memory is managed by Rust code, and Lua only holds a
|
||||
/// reference to it. This can be used to avoid copying large strings into Lua memory.
|
||||
#[cfg(feature = "lua55")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "lua55")))]
|
||||
#[inline]
|
||||
pub fn create_external_string(&self, s: impl Into<Vec<u8>>) -> Result<String> {
|
||||
unsafe { self.lock().create_external_string(s.into()) }
|
||||
}
|
||||
|
||||
/// Creates and returns a Luau [buffer] object from a byte slice of data.
|
||||
///
|
||||
/// [buffer]: https://luau.org/library#buffer-library
|
||||
|
||||
@@ -529,6 +529,23 @@ impl RawLua {
|
||||
Ok(String(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> {
|
||||
let state = self.state();
|
||||
if self.unlikely_memory_error() {
|
||||
crate::util::push_external_string(state, bytes, false)?;
|
||||
return Ok(String(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()))
|
||||
}
|
||||
|
||||
#[cfg(feature = "luau")]
|
||||
pub(crate) unsafe fn create_buffer_with_capacity(&self, size: usize) -> Result<(*mut u8, crate::Buffer)> {
|
||||
let state = self.state();
|
||||
|
||||
@@ -99,6 +99,38 @@ pub(crate) unsafe fn push_string(state: *mut ffi::lua_State, s: &[u8], protect:
|
||||
}
|
||||
}
|
||||
|
||||
// Uses 3 (or 1 if unprotected) stack spaces, does not call checkstack.
|
||||
#[cfg(feature = "lua55")]
|
||||
pub(crate) unsafe fn push_external_string(
|
||||
state: *mut ffi::lua_State,
|
||||
mut bytes: Vec<u8>,
|
||||
protect: bool,
|
||||
) -> Result<()> {
|
||||
bytes.push(0);
|
||||
let s_len = bytes.len() - 1; // exclude null terminator
|
||||
let s_ptr = bytes.as_ptr() as *const c_char;
|
||||
let bytes_ud = Box::into_raw(Box::new(bytes));
|
||||
|
||||
unsafe extern "C" fn dealloc(ud: *mut c_void, _: *mut c_void, _: usize, _: usize) -> *mut c_void {
|
||||
drop(Box::from_raw(ud as *mut Vec<u8>));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
if protect {
|
||||
let res = protect_lua!(state, 0, 1, move |state| {
|
||||
ffi::lua_pushexternalstring(state, s_ptr, s_len, Some(dealloc), bytes_ud as *mut _);
|
||||
});
|
||||
if res.is_err() {
|
||||
// Deallocate on error
|
||||
drop(Box::from_raw(bytes_ud));
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
ffi::lua_pushexternalstring(state, s_ptr, s_len, Some(dealloc), bytes_ud as *mut _);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Uses 3 stack spaces (when protect), does not call checkstack.
|
||||
#[cfg(feature = "luau")]
|
||||
#[inline(always)]
|
||||
|
||||
Reference in New Issue
Block a user