use std::borrow::Cow; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::convert::TryInto; use std::ffi::{CStr, CString}; use std::hash::{BuildHasher, Hash}; use std::string::String as StdString; use bstr::{BStr, BString}; use num_traits::cast; use crate::error::{Error, Result}; use crate::function::{Function, WrappedFunction}; use crate::lua::Lua; use crate::string::String; use crate::table::Table; use crate::thread::Thread; use crate::types::{LightUserData, MaybeSend}; use crate::userdata::{AnyUserData, UserData, UserDataRef, UserDataRefMut}; use crate::value::{FromLua, IntoLua, Nil, Value}; #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] use crate::{function::OwnedFunction, table::OwnedTable, userdata::OwnedAnyUserData}; #[cfg(feature = "async")] use crate::function::WrappedAsyncFunction; impl<'lua> IntoLua<'lua> for Value<'lua> { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { Ok(self) } } impl<'lua> FromLua<'lua> for Value<'lua> { #[inline] fn from_lua(lua_value: Value<'lua>, _: &'lua Lua) -> Result { Ok(lua_value) } } impl<'lua> From> for Value<'lua> { #[inline] fn from(value: String<'lua>) -> Self { Value::String(value) } } impl<'lua> IntoLua<'lua> for String<'lua> { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { Ok(self.into()) } } impl<'lua> FromLua<'lua> for String<'lua> { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result> { match value { Value::String(s) => Ok(s), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "string", message: None, }), } } } impl<'lua> From> for Value<'lua> { #[inline] fn from(value: Table<'lua>) -> Self { Value::Table(value) } } impl<'lua> IntoLua<'lua> for Table<'lua> { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { Ok(self.into()) } } impl<'lua> FromLua<'lua> for Table<'lua> { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result> { match value { Value::Table(table) => Ok(table), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "table", message: None, }), } } } #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] impl<'lua> IntoLua<'lua> for OwnedTable { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::Table(Table(lua.adopt_owned_ref(self.0)))) } } #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] impl<'lua> FromLua<'lua> for OwnedTable { #[inline] fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result { Table::from_lua(value, lua).map(|s| s.into_owned()) } } impl<'lua> From> for Value<'lua> { #[inline] fn from(value: Function<'lua>) -> Self { Value::Function(value) } } impl<'lua> IntoLua<'lua> for Function<'lua> { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { Ok(self.into()) } } impl<'lua> FromLua<'lua> for Function<'lua> { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result> { match value { Value::Function(table) => Ok(table), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "function", message: None, }), } } } #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] impl<'lua> IntoLua<'lua> for OwnedFunction { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::Function(Function(lua.adopt_owned_ref(self.0)))) } } #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] impl<'lua> FromLua<'lua> for OwnedFunction { #[inline] fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result { Function::from_lua(value, lua).map(|s| s.into_owned()) } } impl<'lua> IntoLua<'lua> for WrappedFunction<'lua> { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { lua.create_callback(self.0).map(Value::Function) } } #[cfg(feature = "async")] impl<'lua> IntoLua<'lua> for WrappedAsyncFunction<'lua> { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { lua.create_async_callback(self.0).map(Value::Function) } } impl<'lua> From> for Value<'lua> { #[inline] fn from(value: Thread<'lua>) -> Self { Value::Thread(value) } } impl<'lua> IntoLua<'lua> for Thread<'lua> { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { Ok(self.into()) } } impl<'lua> FromLua<'lua> for Thread<'lua> { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result> { match value { Value::Thread(t) => Ok(t), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "thread", message: None, }), } } } impl<'lua> From> for Value<'lua> { #[inline] fn from(value: AnyUserData<'lua>) -> Self { Value::UserData(value) } } impl<'lua> IntoLua<'lua> for AnyUserData<'lua> { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { Ok(self.into()) } } impl<'lua> FromLua<'lua> for AnyUserData<'lua> { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result> { match value { Value::UserData(ud) => Ok(ud), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "userdata", message: None, }), } } } #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] impl<'lua> IntoLua<'lua> for OwnedAnyUserData { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::UserData(AnyUserData(lua.adopt_owned_ref(self.0)))) } } #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))] #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))] impl<'lua> FromLua<'lua> for OwnedAnyUserData { #[inline] fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result { AnyUserData::from_lua(value, lua).map(|s| s.into_owned()) } } impl<'lua, T: 'static + MaybeSend + UserData> IntoLua<'lua> for T { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::UserData(lua.create_userdata(self)?)) } } impl<'lua, T: 'static> FromLua<'lua> for UserDataRef<'lua, T> { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { Self::from_value(value) } } impl<'lua, T: 'static> FromLua<'lua> for UserDataRefMut<'lua, T> { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { Self::from_value(value) } } impl<'lua> From for Value<'lua> { #[inline] fn from(value: Error) -> Self { Value::Error(value) } } impl<'lua> IntoLua<'lua> for Error { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { Ok(self.into()) } } impl<'lua> FromLua<'lua> for Error { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { match value { Value::Error(err) => Ok(err), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "error", message: None, }), } } } impl<'lua> From for Value<'lua> { #[inline] fn from(value: bool) -> Self { Value::Boolean(value) } } impl<'lua> IntoLua<'lua> for bool { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { Ok(self.into()) } } impl<'lua> FromLua<'lua> for bool { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { match value { Value::Nil => Ok(false), Value::Boolean(b) => Ok(b), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "boolean", message: None, }), } } } impl<'lua> From for Value<'lua> { #[inline] fn from(value: LightUserData) -> Self { Value::LightUserData(value) } } impl<'lua> IntoLua<'lua> for LightUserData { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { Ok(self.into()) } } impl<'lua> FromLua<'lua> for LightUserData { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { match value { Value::LightUserData(ud) => Ok(ud), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "light userdata", message: None, }), } } } #[cfg(feature = "luau")] impl<'lua> From for Value<'lua> { #[inline] fn from(value: crate::types::Vector) -> Self { Value::Vector(value) } } #[cfg(feature = "luau")] impl<'lua> IntoLua<'lua> for crate::types::Vector { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { Ok(Value::Vector(self)) } } #[cfg(feature = "luau")] impl<'lua> FromLua<'lua> for crate::types::Vector { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { match value { Value::Vector(v) => Ok(v), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "vector", message: None, }), } } } impl<'lua> IntoLua<'lua> for StdString { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::String(lua.create_string(&self)?)) } } impl<'lua> FromLua<'lua> for StdString { #[inline] fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result { let s = String::from_lua(value, lua)?; Ok(s.to_str()?.to_owned()) } } impl<'lua> IntoLua<'lua> for &str { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::String(lua.create_string(self)?)) } } impl<'lua> IntoLua<'lua> for Cow<'_, str> { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::String(lua.create_string(self.as_bytes())?)) } } impl<'lua> IntoLua<'lua> for Box { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::String(lua.create_string(&*self)?)) } } impl<'lua> FromLua<'lua> for Box { #[inline] fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result { StdString::from_lua(value, lua).map(|s| s.into_boxed_str()) } } impl<'lua> IntoLua<'lua> for CString { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::String(lua.create_string(self.as_bytes())?)) } } impl<'lua> FromLua<'lua> for CString { #[inline] fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result { let s = String::from_lua(value, lua)?; match CStr::from_bytes_with_nul(s.as_bytes_with_nul()) { Ok(s) => Ok(s.to_owned()), Err(e) => Err(Error::FromLuaConversionError { from: "string", to: "CString", message: Some(e.to_string()), }), } } } impl<'lua> IntoLua<'lua> for &CStr { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::String(lua.create_string(self.to_bytes())?)) } } impl<'lua> IntoLua<'lua> for Cow<'_, CStr> { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::String(lua.create_string(self.to_bytes())?)) } } impl<'lua> IntoLua<'lua> for BString { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::String(lua.create_string(&self)?)) } } impl<'lua> FromLua<'lua> for BString { #[inline] fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result { let s = String::from_lua(value, lua)?; Ok(BString::from(s.as_bytes().to_vec())) } } impl<'lua> IntoLua<'lua> for &BStr { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::String(lua.create_string(self)?)) } } macro_rules! lua_convert_int_infallible { ($($x:ty),*) => { $(impl<'lua> From<$x> for Value<'lua> { #[inline] fn from(value: $x) -> Self { Self::Integer(value.into()) } })* } } macro_rules! lua_convert_int { ($($x:ty),*) => { $(impl<'lua> IntoLua<'lua> for $x { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { cast(self) .map(Value::Integer) .or_else(|| cast(self).map(Value::Number)) // This is impossible error because conversion to Number never fails .ok_or_else(|| Error::ToLuaConversionError { from: stringify!($x), to: "number", message: Some("out of range".to_owned()), }) } } impl<'lua> FromLua<'lua> for $x { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { (match value { Value::Integer(i) => cast(i), Value::Number(n) => cast(n), _ => return Err(Error::FromLuaConversionError { from: value.type_name(), to: stringify!($x), message: None, }), }) .ok_or_else(|| Error::FromLuaConversionError { from: value.type_name(), to: stringify!($x), message: Some("out of range".to_owned()), }) } })* }; } lua_convert_int!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); lua_convert_int_infallible!(i8, u8, i16, u16, i32); macro_rules! lua_convert_float { ($($x:ty),*) => { $(impl<'lua> IntoLua<'lua> for $x { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { cast(self) .ok_or_else(|| Error::ToLuaConversionError { from: stringify!($x), to: "number", message: Some("out of range".to_string()), }) .map(Value::Number) } } impl<'lua> FromLua<'lua> for $x { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { (match value { Value::Integer(i) => cast(i), Value::Number(n) => cast(n), _ => return Err(Error::FromLuaConversionError { from: value.type_name(), to: stringify!($x), message: None, }), }) .ok_or_else(|| Error::FromLuaConversionError { from: value.type_name(), to: stringify!($x), message: Some("out of range".to_owned()), }) } })* }; } lua_convert_float!(f32, f64); impl<'lua, T> IntoLua<'lua> for &[T] where T: Clone + IntoLua<'lua>, { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::Table( lua.create_sequence_from(self.iter().cloned())?, )) } } impl<'lua, T, const N: usize> IntoLua<'lua> for [T; N] where T: IntoLua<'lua>, { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::Table(lua.create_sequence_from(self)?)) } } impl<'lua, T, const N: usize> FromLua<'lua> for [T; N] where T: FromLua<'lua>, { #[inline] fn from_lua(value: Value<'lua>, _lua: &'lua Lua) -> Result { match value { #[cfg(feature = "luau")] #[rustfmt::skip] Value::Vector(v) if N == crate::types::Vector::SIZE => unsafe { use std::{mem, ptr}; let mut arr: [mem::MaybeUninit; N] = mem::MaybeUninit::uninit().assume_init(); ptr::write(arr[0].as_mut_ptr() , T::from_lua(Value::Number(v.x() as _), _lua)?); ptr::write(arr[1].as_mut_ptr(), T::from_lua(Value::Number(v.y() as _), _lua)?); ptr::write(arr[2].as_mut_ptr(), T::from_lua(Value::Number(v.z() as _), _lua)?); #[cfg(feature = "luau-vector4")] ptr::write(arr[3].as_mut_ptr(), T::from_lua(Value::Number(v.w() as _), _lua)?); Ok(mem::transmute_copy(&arr)) }, Value::Table(table) => { let vec = table.sequence_values().collect::>>()?; vec.try_into() .map_err(|vec: Vec| Error::FromLuaConversionError { from: "Table", to: "Array", message: Some(format!("expected table of length {}, got {}", N, vec.len())), }) } _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "Array", message: Some("expected table".to_string()), }), } } } impl<'lua, T: IntoLua<'lua>> IntoLua<'lua> for Box<[T]> { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::Table(lua.create_sequence_from(self.into_vec())?)) } } impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Box<[T]> { #[inline] fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result { Ok(Vec::::from_lua(value, lua)?.into_boxed_slice()) } } impl<'lua, T: IntoLua<'lua>> IntoLua<'lua> for Vec { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::Table(lua.create_sequence_from(self)?)) } } impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Vec { #[inline] fn from_lua(value: Value<'lua>, _lua: &'lua Lua) -> Result { match value { Value::Table(table) => table.sequence_values().collect(), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "Vec", message: Some("expected table".to_string()), }), } } } impl<'lua, K: Eq + Hash + IntoLua<'lua>, V: IntoLua<'lua>, S: BuildHasher> IntoLua<'lua> for HashMap { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::Table(lua.create_table_from(self)?)) } } impl<'lua, K: Eq + Hash + FromLua<'lua>, V: FromLua<'lua>, S: BuildHasher + Default> FromLua<'lua> for HashMap { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { if let Value::Table(table) = value { table.pairs().collect() } else { Err(Error::FromLuaConversionError { from: value.type_name(), to: "HashMap", message: Some("expected table".to_string()), }) } } } impl<'lua, K: Ord + IntoLua<'lua>, V: IntoLua<'lua>> IntoLua<'lua> for BTreeMap { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::Table(lua.create_table_from(self)?)) } } impl<'lua, K: Ord + FromLua<'lua>, V: FromLua<'lua>> FromLua<'lua> for BTreeMap { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { if let Value::Table(table) = value { table.pairs().collect() } else { Err(Error::FromLuaConversionError { from: value.type_name(), to: "BTreeMap", message: Some("expected table".to_string()), }) } } } impl<'lua, T: Eq + Hash + IntoLua<'lua>, S: BuildHasher> IntoLua<'lua> for HashSet { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::Table(lua.create_table_from( self.into_iter().map(|val| (val, true)), )?)) } } impl<'lua, T: Eq + Hash + FromLua<'lua>, S: BuildHasher + Default> FromLua<'lua> for HashSet { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { match value { Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(), Value::Table(table) => table .pairs::>() .map(|res| res.map(|(k, _)| k)) .collect(), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "HashSet", message: Some("expected table".to_string()), }), } } } impl<'lua, T: Ord + IntoLua<'lua>> IntoLua<'lua> for BTreeSet { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { Ok(Value::Table(lua.create_table_from( self.into_iter().map(|val| (val, true)), )?)) } } impl<'lua, T: Ord + FromLua<'lua>> FromLua<'lua> for BTreeSet { #[inline] fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { match value { Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(), Value::Table(table) => table .pairs::>() .map(|res| res.map(|(k, _)| k)) .collect(), _ => Err(Error::FromLuaConversionError { from: value.type_name(), to: "BTreeSet", message: Some("expected table".to_string()), }), } } } impl<'lua, T: IntoLua<'lua>> IntoLua<'lua> for Option { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { match self { Some(val) => val.into_lua(lua), None => Ok(Nil), } } } impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Option { #[inline] fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result { match value { Nil => Ok(None), value => Ok(Some(T::from_lua(value, lua)?)), } } }