Add OwnedString

This commit is contained in:
Alex Orlenko 2023-04-26 23:17:27 +01:00
parent 21b834decc
commit a1d385c7b7
No known key found for this signature in database
GPG Key ID: 4C150C250863B96D
4 changed files with 84 additions and 3 deletions

View File

@ -152,7 +152,9 @@ extern crate mlua_derive;
// Unstable features
#[cfg(feature = "unstable")]
pub use crate::{function::OwnedFunction, table::OwnedTable, userdata::OwnedAnyUserData};
pub use crate::{
function::OwnedFunction, string::OwnedString, table::OwnedTable, userdata::OwnedAnyUserData,
};
/// Create a type that implements [`AsChunk`] and can capture Rust variables.
///

View File

@ -36,9 +36,9 @@ pub use crate::{
SerializeOptions as LuaSerializeOptions,
};
#[cfg(all(feature = "unstable", not(feature = "send")))]
#[cfg(feature = "unstable")]
#[doc(no_inline)]
pub use crate::{
OwnedAnyUserData as LuaOwnedAnyUserData, OwnedFunction as LuaOwnedFunction,
OwnedTable as LuaOwnedTable,
OwnedString as LuaOwnedString, OwnedTable as LuaOwnedTable,
};

View File

@ -19,6 +19,27 @@ use crate::types::LuaRef;
#[derive(Clone)]
pub struct String<'lua>(pub(crate) LuaRef<'lua>);
/// Owned handle to an internal Lua string.
///
/// The owned handle holds a *strong* reference to the current Lua instance.
/// Be warned, if you place it into a Lua type (eg. [`UserData`] or a Rust callback), it is *very easy*
/// to accidentally cause reference cycles that would prevent destroying Lua instance.
///
/// [`UserData`]: crate::UserData
#[cfg(feature = "unstable")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
#[derive(Clone)]
pub struct OwnedString(pub(crate) crate::types::LuaOwnedRef);
#[cfg(feature = "unstable")]
impl OwnedString {
/// Get borrowed handle to the underlying Lua string.
#[cfg_attr(feature = "send", allow(unused))]
pub const fn to_ref(&self) -> String {
String(self.0.to_ref())
}
}
impl<'lua> String<'lua> {
/// Get a `&str` slice if the Lua string is valid UTF-8.
///
@ -121,6 +142,14 @@ impl<'lua> String<'lua> {
let ref_thread = self.0.lua.ref_thread();
unsafe { ffi::lua_topointer(ref_thread, self.0.index) }
}
/// Convert this handle to owned version.
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
#[inline]
pub fn into_owned(self) -> OwnedString {
OwnedString(self.0.into_owned())
}
}
impl<'lua> fmt::Debug for String<'lua> {
@ -202,6 +231,37 @@ impl<'lua> Serialize for String<'lua> {
}
}
// Additional shortcuts
#[cfg(feature = "unstable")]
impl OwnedString {
/// Get a `&str` slice if the Lua string is valid UTF-8.
///
/// This is a shortcut for [`String::to_str()`].
#[inline]
pub fn to_str(&self) -> Result<&str> {
let s = self.to_ref();
// Reattach lifetime to &self
unsafe { std::mem::transmute(s.to_str()) }
}
/// Get the bytes that make up this string.
///
/// This is a shortcut for [`String::as_bytes()`].
#[inline]
pub fn as_bytes(&self) -> &[u8] {
let s = self.to_ref();
// Reattach lifetime to &self
unsafe { std::mem::transmute(s.as_bytes()) }
}
}
#[cfg(feature = "unstable")]
impl fmt::Debug for OwnedString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_ref().fmt(f)
}
}
#[cfg(test)]
mod assertions {
use super::*;

View File

@ -98,3 +98,22 @@ fn test_string_debug() -> Result<()> {
Ok(())
}
#[cfg(all(feature = "unstable", not(feature = "send")))]
#[test]
fn test_owned_string() -> Result<()> {
let lua = Lua::new();
let s = lua.create_string("hello, world!")?.into_owned();
drop(lua);
// Shortcuts
assert_eq!(s.as_bytes(), b"hello, world!");
assert_eq!(s.to_str()?, "hello, world!");
assert_eq!(format!("{s:?}"), "\"hello, world!\"");
// Access via reference
assert_eq!(s.to_ref().to_string_lossy(), "hello, world!");
Ok(())
}