use luau_common::{BStr, BString};
use luau_vm::thread::{StackGuard, Thread as VmThread};
use super::LuaString;
use crate::error::Error;
use crate::thread::Thread;
use crate::value::{FromLua, IntoLua, LuaType, Value};
struct WrappedString<T>(T);
impl LuaString<'_> {
pub fn wrap<T>(data: T) -> impl for<'value> IntoLua<'value>
where
T: AsRef<[u8]>,
{
WrappedString(data)
}
}
impl LuaType for LuaString<'_> {
fn push_type_key(thread: impl AsRef<VmThread>) -> Result<(), Error> {
let thread = thread.as_ref();
unsafe {
thread
.push_string("")
.map_err(|exit| Error::from_thread_exit(thread, exit))
}
}
}
impl<'lua> IntoLua<'lua> for &str {
fn into_lua(self, thread: crate::LuaRef<'lua>) -> Result<Value<'lua>, Error> {
LuaString::from_bytes(&thread.current_thread(), self).map(Value::String)
}
unsafe fn push_into_stack(self, thread: &Thread<'lua>) -> Result<(), Error> {
unsafe {
thread
.as_vm()
.push_string(self)
.map_err(|exit| Error::from_thread_exit(thread, exit))?;
}
Ok(())
}
}
impl<'lua> IntoLua<'lua> for String {
fn into_lua(self, thread: crate::LuaRef<'lua>) -> Result<Value<'lua>, Error> {
LuaString::from_bytes(&thread.current_thread(), self).map(Value::String)
}
unsafe fn push_into_stack(self, thread: &Thread<'lua>) -> Result<(), Error> {
unsafe {
thread
.as_vm()
.push_string(self)
.map_err(|exit| Error::from_thread_exit(thread, exit))?;
}
Ok(())
}
}
impl<'lua> IntoLua<'lua> for &String {
fn into_lua(self, thread: crate::LuaRef<'lua>) -> Result<Value<'lua>, Error> {
self.as_str().into_lua(thread)
}
unsafe fn push_into_stack(self, thread: &Thread<'lua>) -> Result<(), Error> {
unsafe { self.as_str().push_into_stack(thread) }
}
}
impl<'lua> IntoLua<'lua> for &[u8] {
fn into_lua(self, thread: crate::LuaRef<'lua>) -> Result<Value<'lua>, Error> {
LuaString::from_bytes(&thread.current_thread(), self).map(Value::String)
}
unsafe fn push_into_stack(self, thread: &Thread<'lua>) -> Result<(), Error> {
unsafe {
thread
.as_vm()
.push_string(self)
.map_err(|exit| Error::from_thread_exit(thread, exit))?;
}
Ok(())
}
}
impl<'lua> IntoLua<'lua> for &BStr {
fn into_lua(self, thread: crate::LuaRef<'lua>) -> Result<Value<'lua>, Error> {
LuaString::from_bytes(&thread.current_thread(), self).map(Value::String)
}
unsafe fn push_into_stack(self, thread: &Thread<'lua>) -> Result<(), Error> {
unsafe {
thread
.as_vm()
.push_string(self)
.map_err(|exit| Error::from_thread_exit(thread, exit))?;
}
Ok(())
}
}
impl<'lua> IntoLua<'lua> for BString {
fn into_lua(self, thread: crate::LuaRef<'lua>) -> Result<Value<'lua>, Error> {
LuaString::from_bytes(&thread.current_thread(), &self).map(Value::String)
}
unsafe fn push_into_stack(self, thread: &Thread<'lua>) -> Result<(), Error> {
unsafe {
thread
.as_vm()
.push_string(self)
.map_err(|exit| Error::from_thread_exit(thread, exit))?;
}
Ok(())
}
}
impl<'lua> IntoLua<'lua> for &BString {
fn into_lua(self, thread: crate::LuaRef<'lua>) -> Result<Value<'lua>, Error> {
LuaString::from_bytes(&thread.current_thread(), self).map(Value::String)
}
unsafe fn push_into_stack(self, thread: &Thread<'lua>) -> Result<(), Error> {
unsafe {
thread
.as_vm()
.push_string(self)
.map_err(|exit| Error::from_thread_exit(thread, exit))?;
}
Ok(())
}
}
impl<'lua, 'string> IntoLua<'lua> for LuaString<'string>
where
'string: 'lua,
{
fn into_lua(self, _: crate::LuaRef<'lua>) -> Result<Value<'lua>, Error> {
Ok(Value::String(self))
}
unsafe fn push_into_stack(self, thread: &Thread<'lua>) -> Result<(), Error> {
self.push_to(thread)
}
}
impl<'lua, 'string> IntoLua<'lua> for &LuaString<'string>
where
'string: 'lua,
{
fn into_lua(self, _: crate::LuaRef<'lua>) -> Result<Value<'lua>, Error> {
Ok(Value::String(self.try_clone()?))
}
unsafe fn push_into_stack(self, thread: &Thread<'lua>) -> Result<(), Error> {
self.push_to(thread)
}
}
impl<'lua> FromLua<'lua> for LuaString<'lua> {
fn from_lua(value: Value<'lua>, lua: crate::LuaRef<'lua>) -> Result<Self, Error> {
match value {
Value::String(value) => Ok(value),
value => {
let thread = lua.current_thread();
let vm_thread = thread.as_vm();
unsafe {
let _stack = StackGuard::new(vm_thread);
value.push_to(&thread)?;
LuaString::coerce_from_stack(&thread, -1)
}
}
}
}
unsafe fn from_stack(thread: &Thread<'lua>, index: i32) -> Result<Self, Error> {
LuaString::coerce_from_stack(thread, index)
}
}
impl<'lua> FromLua<'lua> for BString {
fn from_lua(value: Value<'lua>, lua: crate::LuaRef<'lua>) -> Result<Self, Error> {
match value {
Value::String(value) => Ok(value.as_bytes().to_owned()),
Value::Buffer(value) => Ok(value.to_vec().into()),
value => LuaString::from_lua(value, lua).map(|value| value.as_bytes().to_owned()),
}
}
unsafe fn from_stack(thread: &Thread<'lua>, index: i32) -> Result<Self, Error> {
if let Some((data, len)) = unsafe { thread.as_vm().to_buffer(index) } {
if len == 0 {
return Ok(BString::default());
}
let bytes = unsafe { core::slice::from_raw_parts(data.cast_const(), len) };
return Ok(bytes.into());
}
let value = LuaString::coerce_from_stack(thread, index)?;
Ok(value.as_bytes().to_owned())
}
}
impl<'lua> FromLua<'lua> for String {
fn from_lua(value: Value<'lua>, lua: crate::LuaRef<'lua>) -> Result<Self, Error> {
let value = LuaString::from_lua(value, lua)?;
value.to_str().map(str::to_owned)
}
unsafe fn from_stack(thread: &Thread<'lua>, index: i32) -> Result<Self, Error> {
let value = LuaString::coerce_from_stack(thread, index)?;
value.to_str().map(str::to_owned)
}
}
impl<'lua, T> IntoLua<'lua> for WrappedString<T>
where
T: AsRef<[u8]>,
{
fn into_lua(self, thread: crate::LuaRef<'lua>) -> Result<Value<'lua>, Error> {
LuaString::from_bytes(&thread.current_thread(), self.0).map(Value::String)
}
unsafe fn push_into_stack(self, thread: &Thread<'lua>) -> Result<(), Error> {
unsafe {
thread
.as_vm()
.push_string(self.0)
.map_err(|exit| Error::from_thread_exit(thread, exit))?;
}
Ok(())
}
}