mirror of
https://github.com/mlua-rs/mlua
synced 2026-06-08 16:05:43 +00:00
Better Luau buffer type support.
- Add `Lua::create_buffer()` function - Support serializing buffer type as a byte slice - Support accessing copy of underlying bytes using `BString`
This commit is contained in:
+35
-5
@@ -679,19 +679,49 @@ impl<'lua> IntoLua<'lua> for BString {
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for BString {
|
||||
#[inline]
|
||||
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
|
||||
let ty = value.type_name();
|
||||
Ok(BString::from(
|
||||
lua.coerce_string(value)?
|
||||
match value {
|
||||
Value::String(s) => Ok(s.as_bytes().into()),
|
||||
#[cfg(feature = "luau")]
|
||||
Value::UserData(ud) if ud.1 == crate::types::SubtypeId::Buffer => unsafe {
|
||||
let mut size = 0usize;
|
||||
let buf = ffi::lua_tobuffer(ud.0.lua.ref_thread(), ud.0.index, &mut size);
|
||||
mlua_assert!(!buf.is_null(), "invalid Luau buffer");
|
||||
Ok(slice::from_raw_parts(buf as *const u8, size).into())
|
||||
},
|
||||
_ => Ok(lua
|
||||
.coerce_string(value)?
|
||||
.ok_or_else(|| Error::FromLuaConversionError {
|
||||
from: ty,
|
||||
to: "BString",
|
||||
message: Some("expected string or number".to_string()),
|
||||
})?
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
))
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn from_stack(idx: c_int, lua: &'lua Lua) -> Result<Self> {
|
||||
let state = lua.state();
|
||||
match ffi::lua_type(state, idx) {
|
||||
ffi::LUA_TSTRING => {
|
||||
let mut size = 0;
|
||||
let data = ffi::lua_tolstring(state, idx, &mut size);
|
||||
Ok(slice::from_raw_parts(data as *const u8, size).into())
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
ffi::LUA_TBUFFER => {
|
||||
let mut size = 0;
|
||||
let buf = ffi::lua_tobuffer(state, idx, &mut size);
|
||||
mlua_assert!(!buf.is_null(), "invalid Luau buffer");
|
||||
Ok(slice::from_raw_parts(buf as *const u8, size).into())
|
||||
}
|
||||
_ => {
|
||||
// Fallback to default
|
||||
Self::from_lua(lua.stack_value(idx), lua)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+21
@@ -1373,6 +1373,27 @@ impl Lua {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create and return a Luau [buffer] object from a byte slice of data.
|
||||
///
|
||||
/// Requires `feature = "luau"`
|
||||
///
|
||||
/// [buffer]: https://luau-lang.org/library#buffer-library
|
||||
#[cfg(feature = "luau")]
|
||||
pub fn create_buffer(&self, buf: impl AsRef<[u8]>) -> Result<AnyUserData> {
|
||||
let state = self.state();
|
||||
unsafe {
|
||||
if self.unlikely_memory_error() {
|
||||
crate::util::push_buffer(self.ref_thread(), buf.as_ref(), false)?;
|
||||
return Ok(AnyUserData(self.pop_ref_thread(), SubtypeId::Buffer));
|
||||
}
|
||||
|
||||
let _sg = StackGuard::new(state);
|
||||
check_stack(state, 4)?;
|
||||
crate::util::push_buffer(state, buf.as_ref(), true)?;
|
||||
Ok(AnyUserData(self.pop_ref(), SubtypeId::Buffer))
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates and returns a new empty table.
|
||||
pub fn create_table(&self) -> Result<Table> {
|
||||
self.create_table_with_capacity(0, 0)
|
||||
|
||||
@@ -148,6 +148,14 @@ impl<'lua, 'de> serde::Deserializer<'de> for Deserializer<'lua> {
|
||||
Value::UserData(ud) if ud.is_serializable() => {
|
||||
serde_userdata(ud, |value| value.deserialize_any(visitor))
|
||||
}
|
||||
#[cfg(feature = "luau")]
|
||||
Value::UserData(ud) if ud.1 == crate::types::SubtypeId::Buffer => unsafe {
|
||||
let mut size = 0usize;
|
||||
let buf = ffi::lua_tobuffer(ud.0.lua.ref_thread(), ud.0.index, &mut size);
|
||||
mlua_assert!(!buf.is_null(), "invalid Luau buffer");
|
||||
let buf = std::slice::from_raw_parts(buf as *const u8, size);
|
||||
visitor.visit_bytes(buf)
|
||||
},
|
||||
Value::Function(_)
|
||||
| Value::Thread(_)
|
||||
| Value::UserData(_)
|
||||
|
||||
@@ -1340,6 +1340,19 @@ impl<'lua> Serialize for AnyUserData<'lua> {
|
||||
S: Serializer,
|
||||
{
|
||||
let lua = self.0.lua;
|
||||
|
||||
// Special case for Luau buffer type
|
||||
#[cfg(feature = "luau")]
|
||||
if self.1 == SubtypeId::Buffer {
|
||||
let buf = unsafe {
|
||||
let mut size = 0usize;
|
||||
let buf = ffi::lua_tobuffer(lua.ref_thread(), self.0.index, &mut size);
|
||||
mlua_assert!(!buf.is_null(), "invalid Luau buffer");
|
||||
std::slice::from_raw_parts(buf as *const u8, size)
|
||||
};
|
||||
return serializer.serialize_bytes(buf);
|
||||
}
|
||||
|
||||
let data = unsafe {
|
||||
let _ = lua
|
||||
.get_userdata_ref_type_id(&self.0)
|
||||
|
||||
@@ -253,6 +253,20 @@ pub unsafe fn push_string(state: *mut ffi::lua_State, s: &[u8], protect: bool) -
|
||||
}
|
||||
}
|
||||
|
||||
// Uses 3 stack spaces (when protect), does not call checkstack.
|
||||
#[cfg(feature = "luau")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn push_buffer(state: *mut ffi::lua_State, b: &[u8], protect: bool) -> Result<()> {
|
||||
let data = if protect {
|
||||
protect_lua!(state, 0, 1, |state| ffi::lua_newbuffer(state, b.len()))?
|
||||
} else {
|
||||
ffi::lua_newbuffer(state, b.len())
|
||||
};
|
||||
let buf = slice::from_raw_parts_mut(data as *mut u8, b.len());
|
||||
buf.copy_from_slice(b);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Uses 3 stack spaces, does not call checkstack.
|
||||
#[inline]
|
||||
pub unsafe fn push_table(
|
||||
|
||||
Reference in New Issue
Block a user