From 80b1ecd46de0aab641ae6571b1671dbe5b5cadce Mon Sep 17 00:00:00 2001 From: joshw Date: Fri, 12 Jul 2024 18:37:31 -0500 Subject: [PATCH 01/17] Added a ToLua macro, early stages --- mlua_derive/src/lib.rs | 8 ++++++++ mlua_derive/src/to_lua.rs | 37 +++++++++++++++++++++++++++++++++++++ src/lib.rs | 7 +++++++ 3 files changed, 52 insertions(+) create mode 100644 mlua_derive/src/to_lua.rs diff --git a/mlua_derive/src/lib.rs b/mlua_derive/src/lib.rs index 74605cb9..a496af66 100644 --- a/mlua_derive/src/lib.rs +++ b/mlua_derive/src/lib.rs @@ -153,9 +153,17 @@ pub fn from_lua(input: TokenStream) -> TokenStream { from_lua::from_lua(input) } +#[cfg(feature = "macros")] +#[proc_macro_derive(ToLua)] +pub fn to_lua(input: TokenStream) -> TokenStream { + to_lua::to_lua(input) +} + #[cfg(feature = "macros")] mod chunk; #[cfg(feature = "macros")] mod from_lua; #[cfg(feature = "macros")] +mod to_lua; +#[cfg(feature = "macros")] mod token; diff --git a/mlua_derive/src/to_lua.rs b/mlua_derive/src/to_lua.rs new file mode 100644 index 00000000..9924a1a4 --- /dev/null +++ b/mlua_derive/src/to_lua.rs @@ -0,0 +1,37 @@ +use proc_macro::TokenStream; +use quote::{quote, format_ident}; +use syn::{parse_macro_input, DeriveInput, Data, Fields}; + +pub fn to_lua(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let ident = input.ident; + + let fields = if let Data::Struct(data_struct) = input.data { + match data_struct.fields { + Fields::Named(fields) => fields, + _ => panic!("ToLua can only be derived for structs with named fields"), + } + } else { + panic!("ToLua can only be derived for structs"); + }; + + let set_fields = fields.named.iter().map(|field| { + let name = &field.ident; + let name_str = name.as_ref().unwrap().to_string(); + quote! { + table.set(#name_str, self.#name)?; + } + }); + + let gen = quote! { + impl<'lua> ::mlua::IntoLua<'lua> for #ident { + fn into_lua(self, lua: &'lua ::mlua::Lua) -> ::mlua::Result<::mlua::Value<'lua>> { + let table = lua.create_table()?; + #(#set_fields)* + Ok(::mlua::Value::Table(table)) + } + } + }; + + gen.into() +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 9345f5f9..4f9080ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -225,6 +225,13 @@ pub use mlua_derive::chunk; #[cfg_attr(docsrs, doc(cfg(feature = "macros")))] pub use mlua_derive::FromLua; +/// Derive [`ToLua`] for a Rust type. +/// +/// Nested types require [`IntoLua`] as well +#[cfg(feature = "macros")] +#[cfg_attr(docsrs, doc(cfg(feature = "macros")))] +pub use mlua_derive::ToLua; + /// Registers Lua module entrypoint. /// /// You can register multiple entrypoints as required. From 71a039939c7b81b6982f215e971c246227b4d143 Mon Sep 17 00:00:00 2001 From: joshw Date: Sat, 13 Jul 2024 12:35:31 -0500 Subject: [PATCH 02/17] updated to use userdata instead of table --- mlua_derive/src/to_lua.rs | 58 +++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/mlua_derive/src/to_lua.rs b/mlua_derive/src/to_lua.rs index 9924a1a4..984185ee 100644 --- a/mlua_derive/src/to_lua.rs +++ b/mlua_derive/src/to_lua.rs @@ -1,6 +1,9 @@ use proc_macro::TokenStream; use quote::{quote, format_ident}; -use syn::{parse_macro_input, DeriveInput, Data, Fields}; +use syn::{parse_macro_input, DeriveInput, Data, Fields, Type}; +use syn::spanned::Spanned; +use syn::punctuated::Punctuated; +use proc_macro2::TokenStream as TokenStream2; pub fn to_lua(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -15,23 +18,60 @@ pub fn to_lua(input: TokenStream) -> TokenStream { panic!("ToLua can only be derived for structs"); }; - let set_fields = fields.named.iter().map(|field| { + let add_field_methods = fields.named.iter().map(|field| { let name = &field.ident; let name_str = name.as_ref().unwrap().to_string(); + let ty = &field.ty; + + let get_method = if is_copy_type(ty) { + quote! { + fields.add_field_method_get(#name_str, |_, this| Ok(this.#name)); + } + } else { + quote! { + fields.add_field_method_get(#name_str, |_, this| Ok(this.#name.clone())); + } + }; + + let set_method = quote! { + fields.add_field_method_set(#name_str, |_, this, val| { + this.#name = val; + Ok(()) + }); + }; + quote! { - table.set(#name_str, self.#name)?; + #get_method + #set_method } }); let gen = quote! { - impl<'lua> ::mlua::IntoLua<'lua> for #ident { - fn into_lua(self, lua: &'lua ::mlua::Lua) -> ::mlua::Result<::mlua::Value<'lua>> { - let table = lua.create_table()?; - #(#set_fields)* - Ok(::mlua::Value::Table(table)) + impl ::mlua::UserData for #ident { + fn add_fields<'lua, F: ::mlua::prelude::LuaUserDataFields<'lua, Self>>(fields: &mut F) { + #(#add_field_methods)* } } }; gen.into() -} \ No newline at end of file +} + +// I don't know how to determine whether or not something implements copy, so for now everything +// will be cloned that isn't one of these copyable primitives. +fn is_copy_type(ty: &Type) -> bool { + match ty { + Type::Path(type_path) => { + let segments = &type_path.path.segments; + let segment = segments.last().unwrap(); + match segment.ident.to_string().as_str() { + "u8" | "u16" | "u32" | "u64" | "u128" | + "i8" | "i16" | "i32" | "i64" | "i128" | + "f32" | "f64" | + "bool" | "char" | "usize" | "isize" => true, + _ => false, + } + } + _ => false, + } +} From 7a4fc062e3c8779df9dc299d887028e87e4adc74 Mon Sep 17 00:00:00 2001 From: joshw Date: Sat, 13 Jul 2024 13:23:03 -0500 Subject: [PATCH 03/17] ToLuaTable and FromLuaTable macros --- mlua_derive/src/from_lua_table.rs | 45 +++++++++++++++++++++++++++++++ mlua_derive/src/lib.rs | 16 +++++++++++ mlua_derive/src/to_lua_table.rs | 37 +++++++++++++++++++++++++ src/lib.rs | 8 ++++++ 4 files changed, 106 insertions(+) create mode 100644 mlua_derive/src/from_lua_table.rs create mode 100644 mlua_derive/src/to_lua_table.rs diff --git a/mlua_derive/src/from_lua_table.rs b/mlua_derive/src/from_lua_table.rs new file mode 100644 index 00000000..ef5969fe --- /dev/null +++ b/mlua_derive/src/from_lua_table.rs @@ -0,0 +1,45 @@ +use proc_macro::TokenStream; +use quote::{quote, format_ident}; +use syn::{parse_macro_input, DeriveInput, Data, Fields}; + +pub fn from_lua_table(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let ident = input.ident; + + let fields = if let Data::Struct(data_struct) = input.data { + match data_struct.fields { + Fields::Named(fields) => fields, + _ => panic!("FromLuaTable can only be derived for structs with named fields"), + } + } else { + panic!("FromLuaTable can only be derived for structs"); + }; + + let get_fields = fields.named.iter().map(|field| { + let name = &field.ident; + let name_str = name.as_ref().unwrap().to_string(); + quote! { + #name: table.get(#name_str)?, + } + }); + + let gen = quote! { + impl<'lua> ::mlua::FromLua<'lua> for #ident { + fn from_lua(lua_value: ::mlua::Value<'lua>, lua: &'lua ::mlua::Lua) -> ::mlua::Result { + if let ::mlua::Value::Table(table) = lua_value { + Ok(Self { + #(#get_fields)* + }) + } else { + Err(::mlua::Error::FromLuaConversionError { + from: lua_value.type_name(), + to: stringify!(#ident), + message: Some(String::from("expected a Lua table")), + }) + } + } + } + }; + + gen.into() +} diff --git a/mlua_derive/src/lib.rs b/mlua_derive/src/lib.rs index a496af66..c9ab44eb 100644 --- a/mlua_derive/src/lib.rs +++ b/mlua_derive/src/lib.rs @@ -159,6 +159,18 @@ pub fn to_lua(input: TokenStream) -> TokenStream { to_lua::to_lua(input) } +#[cfg(feature = "macros")] +#[proc_macro_derive(FromLuaTable)] +pub fn from_lua_table(input: TokenStream) -> TokenStream { + from_lua_table::from_lua_table(input) +} + +#[cfg(feature = "macros")] +#[proc_macro_derive(ToLuaTable)] +pub fn to_lua_table(input: TokenStream) -> TokenStream { + to_lua_table::to_lua_table(input) +} + #[cfg(feature = "macros")] mod chunk; #[cfg(feature = "macros")] @@ -166,4 +178,8 @@ mod from_lua; #[cfg(feature = "macros")] mod to_lua; #[cfg(feature = "macros")] +mod from_lua_table; +#[cfg(feature = "macros")] +mod to_lua_table; +#[cfg(feature = "macros")] mod token; diff --git a/mlua_derive/src/to_lua_table.rs b/mlua_derive/src/to_lua_table.rs new file mode 100644 index 00000000..506f08d9 --- /dev/null +++ b/mlua_derive/src/to_lua_table.rs @@ -0,0 +1,37 @@ +use proc_macro::TokenStream; +use quote::{quote, format_ident}; +use syn::{parse_macro_input, DeriveInput, Data, Fields}; + +pub fn to_lua_table(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let ident = input.ident; + + let fields = if let Data::Struct(data_struct) = input.data { + match data_struct.fields { + Fields::Named(fields) => fields, + _ => panic!("ToLua can only be derived for structs with named fields"), + } + } else { + panic!("ToLua can only be derived for structs"); + }; + + let set_fields = fields.named.iter().map(|field| { + let name = &field.ident; + let name_str = name.as_ref().unwrap().to_string(); + quote! { + table.set(#name_str, self.#name)?; + } + }); + + let gen = quote! { + impl<'lua> ::mlua::IntoLua<'lua> for #ident { + fn into_lua(self, lua: &'lua ::mlua::Lua) -> ::mlua::Result<::mlua::Value<'lua>> { + let table = lua.create_table()?; + #(#set_fields)* + Ok(::mlua::Value::Table(table)) + } + } + }; + + gen.into() +} diff --git a/src/lib.rs b/src/lib.rs index 4f9080ab..e9b18c77 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -232,6 +232,14 @@ pub use mlua_derive::FromLua; #[cfg_attr(docsrs, doc(cfg(feature = "macros")))] pub use mlua_derive::ToLua; +#[cfg(feature = "macros")] +#[cfg_attr(docsrs, doc(cfg(feature = "macros")))] +pub use mlua_derive::ToLuaTable; + +#[cfg(feature = "macros")] +#[cfg_attr(docsrs, doc(cfg(feature = "macros")))] +pub use mlua_derive::FromLuaTable; + /// Registers Lua module entrypoint. /// /// You can register multiple entrypoints as required. From fe2d825e33de7fa1483838efdc094cf246292461 Mon Sep 17 00:00:00 2001 From: joshua Date: Mon, 15 Jul 2024 13:04:08 -0500 Subject: [PATCH 04/17] added impl for uuid lua stuff --- Cargo.toml | 2 ++ src/conversion.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 5a065523..aca4ca21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ module = ["dep:mlua_derive", "ffi/module"] async = ["dep:futures-util"] send = [] serialize = ["dep:serde", "dep:erased-serde", "dep:serde-value"] +uuid = ["dep:uuid", "dep:serde"] macros = ["mlua_derive/macros"] unstable = [] @@ -51,6 +52,7 @@ num-traits = { version = "0.2.14" } rustc-hash = "2.0" futures-util = { version = "0.3", optional = true, default-features = false, features = ["std"] } serde = { version = "1.0", optional = true } +uuid = { version = "1.10.0", optional = true, features = ["v7", "serde"]} erased-serde = { version = "0.4", optional = true } serde-value = { version = "0.7", optional = true } parking_lot = { version = "0.12", optional = true } diff --git a/src/conversion.rs b/src/conversion.rs index 6013ebf9..13b454ae 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -520,6 +520,49 @@ impl<'lua> FromLua<'lua> for LightUserData { } } +#[cfg(feature = "uuid")] +impl<'lua> IntoLua<'lua> for uuid::Uuid { + #[inline] + fn into_lua(self, _: &'lua Lua) -> Result> { + Ok(Value::String(self.to_string())) + } +} + +#[cfg(feature = "uuid")] +impl<'lua> IntoLua<'lua> for &uuid::Uuid { + #[inline] + fn into_lua(self, _: &'lua Lua) -> Result> { + Ok(Value::String(self.clone().to_string())) + } + + #[inline] + unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> { + lua.push_ref(&self.0); + Ok(()) + } +} + +#[cfg(feature = "uuid")] +impl<'lua> FromLua<'lua> for uuid::Uuid<'lua> { + #[inline] + fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result> { + let ty = value.type_name(); + let string = lua.coerce_string(value)? + .ok_or_else(|| Error::FromLuaConversionError { + from: ty, + to: "string", + message: Some("expected string or number".to_string()), + }); + match string { + Ok(str) => { + Ok(Uuid::parse_str(str.as_str())) + }, + Err(e) => Err(e) + } + } +} + + #[cfg(feature = "luau")] impl<'lua> IntoLua<'lua> for crate::types::Vector { #[inline] From abe4c19ef2303e706166760a9fcf4bce504ee7c4 Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 15 Jul 2024 13:17:21 -0500 Subject: [PATCH 05/17] added impl for uuid lua stuff --- src/conversion.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/conversion.rs b/src/conversion.rs index 13b454ae..90b3e6b6 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -520,7 +520,7 @@ impl<'lua> FromLua<'lua> for LightUserData { } } -#[cfg(feature = "uuid")] +//#[cfg(feature = "uuid")] impl<'lua> IntoLua<'lua> for uuid::Uuid { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { @@ -528,7 +528,7 @@ impl<'lua> IntoLua<'lua> for uuid::Uuid { } } -#[cfg(feature = "uuid")] +//#[cfg(feature = "uuid")] impl<'lua> IntoLua<'lua> for &uuid::Uuid { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { @@ -537,25 +537,25 @@ impl<'lua> IntoLua<'lua> for &uuid::Uuid { #[inline] unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> { - lua.push_ref(&self.0); + lua.push_ref(&self.to_string().0); Ok(()) } } -#[cfg(feature = "uuid")] +//#[cfg(feature = "uuid")] impl<'lua> FromLua<'lua> for uuid::Uuid<'lua> { #[inline] fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result> { let ty = value.type_name(); - let string = lua.coerce_string(value)? + let string_result = lua.coerce_string(value)? .ok_or_else(|| Error::FromLuaConversionError { from: ty, to: "string", message: Some("expected string or number".to_string()), }); - match string { - Ok(str) => { - Ok(Uuid::parse_str(str.as_str())) + match string_result { + Ok(string) => { + Ok(Uuid::parse_str(string.as_str())) }, Err(e) => Err(e) } From e9d3505cde3264ceedc47bc1e511911102c6af1b Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 15 Jul 2024 13:24:33 -0500 Subject: [PATCH 06/17] added impl for uuid lua stuff --- src/conversion.rs | 72 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/src/conversion.rs b/src/conversion.rs index 90b3e6b6..e71205c2 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -520,28 +520,6 @@ impl<'lua> FromLua<'lua> for LightUserData { } } -//#[cfg(feature = "uuid")] -impl<'lua> IntoLua<'lua> for uuid::Uuid { - #[inline] - fn into_lua(self, _: &'lua Lua) -> Result> { - Ok(Value::String(self.to_string())) - } -} - -//#[cfg(feature = "uuid")] -impl<'lua> IntoLua<'lua> for &uuid::Uuid { - #[inline] - fn into_lua(self, _: &'lua Lua) -> Result> { - Ok(Value::String(self.clone().to_string())) - } - - #[inline] - unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> { - lua.push_ref(&self.to_string().0); - Ok(()) - } -} - //#[cfg(feature = "uuid")] impl<'lua> FromLua<'lua> for uuid::Uuid<'lua> { #[inline] @@ -562,6 +540,56 @@ impl<'lua> FromLua<'lua> for uuid::Uuid<'lua> { } } +//#[cfg(feature = "uuid")] +impl<'lua> IntoLua<'lua> for uuid::Uuid<'lua> { + #[inline] + fn into_lua(self, _: &'lua Lua) -> Result> { + Ok(Value::String(self.to_string())) + } +} + +//#[cfg(feature = "uuid")] +impl<'lua> IntoLua<'lua> for &uuid::Uuid<'lua> { + #[inline] + fn into_lua(self, _: &'lua Lua) -> Result> { + Ok(Value::String(self.clone().to_string())) + } + + #[inline] + unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> { + lua.push_ref(&self.0); + Ok(()) + } +} + + +// impl<'lua> FromLua<'lua> for Value<'lua> { +// #[inline] +// fn from_lua(lua_value: Value<'lua>, _: &'lua Lua) -> Result { +// Ok(lua_value) +// } +// } + +// impl<'lua> IntoLua<'lua> for String<'lua> { +// #[inline] +// fn into_lua(self, _: &'lua Lua) -> Result> { +// Ok(Value::String(self)) +// } +// } + +// impl<'lua> IntoLua<'lua> for &String<'lua> { +// #[inline] +// fn into_lua(self, _: &'lua Lua) -> Result> { +// Ok(Value::String(self.clone())) +// } + +// #[inline] +// unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> { +// lua.push_ref(&self.0); +// Ok(()) +// } +// } + #[cfg(feature = "luau")] impl<'lua> IntoLua<'lua> for crate::types::Vector { From 32e7d4e2021118167411b68e290ee63e0decae0c Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 15 Jul 2024 13:30:25 -0500 Subject: [PATCH 07/17] added impl for uuid lua stuff --- src/conversion.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/conversion.rs b/src/conversion.rs index e71205c2..e0696667 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -521,19 +521,19 @@ impl<'lua> FromLua<'lua> for LightUserData { } //#[cfg(feature = "uuid")] -impl<'lua> FromLua<'lua> for uuid::Uuid<'lua> { +impl<'lua> FromLua<'lua> for uuid::Uuid { #[inline] - fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result> { + fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result { let ty = value.type_name(); let string_result = lua.coerce_string(value)? .ok_or_else(|| Error::FromLuaConversionError { from: ty, to: "string", - message: Some("expected string or number".to_string()), + message: Some("expected string uuid".to_string()), }); match string_result { Ok(string) => { - Ok(Uuid::parse_str(string.as_str())) + Ok(Uuid::parse_str(string.to_str())) }, Err(e) => Err(e) } @@ -541,7 +541,7 @@ impl<'lua> FromLua<'lua> for uuid::Uuid<'lua> { } //#[cfg(feature = "uuid")] -impl<'lua> IntoLua<'lua> for uuid::Uuid<'lua> { +impl<'lua> IntoLua<'lua> for uuid::Uuid { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { Ok(Value::String(self.to_string())) @@ -549,7 +549,7 @@ impl<'lua> IntoLua<'lua> for uuid::Uuid<'lua> { } //#[cfg(feature = "uuid")] -impl<'lua> IntoLua<'lua> for &uuid::Uuid<'lua> { +impl<'lua> IntoLua<'lua> for &uuid::Uuid { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { Ok(Value::String(self.clone().to_string())) From dde426cc89f0464dc3efc6cb81bd9043aece3316 Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 15 Jul 2024 13:36:24 -0500 Subject: [PATCH 08/17] added impl for uuid lua stuff --- src/conversion.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/conversion.rs b/src/conversion.rs index e0696667..a7686e44 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -544,7 +544,8 @@ impl<'lua> FromLua<'lua> for uuid::Uuid { impl<'lua> IntoLua<'lua> for uuid::Uuid { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { - Ok(Value::String(self.to_string())) + let uuid_string: String<'lua> = self.to_string(); + Ok(Value::String(uuid_string)) } } @@ -552,12 +553,13 @@ impl<'lua> IntoLua<'lua> for uuid::Uuid { impl<'lua> IntoLua<'lua> for &uuid::Uuid { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { - Ok(Value::String(self.clone().to_string())) + let uuid_string: String<'lua> = self.clone().to_string(); + Ok(Value::String(uuid_string)) } #[inline] unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> { - lua.push_ref(&self.0); + lua.push_ref(&self); Ok(()) } } From 66f15f31f3b843c9112c675b83cd2108b48f17a0 Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 15 Jul 2024 13:47:27 -0500 Subject: [PATCH 09/17] added impl for uuid lua stuff --- src/conversion.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/conversion.rs b/src/conversion.rs index a7686e44..0fbd5ce3 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -543,8 +543,8 @@ impl<'lua> FromLua<'lua> for uuid::Uuid { //#[cfg(feature = "uuid")] impl<'lua> IntoLua<'lua> for uuid::Uuid { #[inline] - fn into_lua(self, _: &'lua Lua) -> Result> { - let uuid_string: String<'lua> = self.to_string(); + fn into_lua(self, lua: &'lua Lua) -> Result> { + let uuid_string = lua.create_string(self.to_string().as_str())?; Ok(Value::String(uuid_string)) } } @@ -553,13 +553,14 @@ impl<'lua> IntoLua<'lua> for uuid::Uuid { impl<'lua> IntoLua<'lua> for &uuid::Uuid { #[inline] fn into_lua(self, _: &'lua Lua) -> Result> { - let uuid_string: String<'lua> = self.clone().to_string(); + let uuid_string = lua.create_string(self.to_string().as_str())?; Ok(Value::String(uuid_string)) } #[inline] unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> { - lua.push_ref(&self); + let uuid_string = lua.create_string(self.to_string().as_str())?; + lua.push_ref(&uuid_string.0); Ok(()) } } From aff15f7d9b064e685dc6e07f817bcdf53bacf1db Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 15 Jul 2024 13:51:27 -0500 Subject: [PATCH 10/17] added impl for uuid lua stuff --- src/conversion.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conversion.rs b/src/conversion.rs index 0fbd5ce3..1868979f 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -533,7 +533,7 @@ impl<'lua> FromLua<'lua> for uuid::Uuid { }); match string_result { Ok(string) => { - Ok(Uuid::parse_str(string.to_str())) + Ok(uuid::Uuid::parse_str(string.to_str())) }, Err(e) => Err(e) } @@ -552,7 +552,7 @@ impl<'lua> IntoLua<'lua> for uuid::Uuid { //#[cfg(feature = "uuid")] impl<'lua> IntoLua<'lua> for &uuid::Uuid { #[inline] - fn into_lua(self, _: &'lua Lua) -> Result> { + fn into_lua(self, lua: &'lua Lua) -> Result> { let uuid_string = lua.create_string(self.to_string().as_str())?; Ok(Value::String(uuid_string)) } From 8c9a845eda5d8385c351572d69650940a0768e89 Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 15 Jul 2024 13:55:04 -0500 Subject: [PATCH 11/17] added impl for uuid lua stuff --- src/conversion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversion.rs b/src/conversion.rs index 1868979f..9d66fc5a 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -533,7 +533,7 @@ impl<'lua> FromLua<'lua> for uuid::Uuid { }); match string_result { Ok(string) => { - Ok(uuid::Uuid::parse_str(string.to_str())) + Ok(uuid::Uuid::parse_str(string.to_str()?)) }, Err(e) => Err(e) } From 050ce112c6495fefb0994e85a9ee668ba9fb5a69 Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 15 Jul 2024 13:56:29 -0500 Subject: [PATCH 12/17] added impl for uuid lua stuff --- src/conversion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversion.rs b/src/conversion.rs index 9d66fc5a..4b48447e 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -533,7 +533,7 @@ impl<'lua> FromLua<'lua> for uuid::Uuid { }); match string_result { Ok(string) => { - Ok(uuid::Uuid::parse_str(string.to_str()?)) + Ok(uuid::Uuid::parse_str(string.to_str()?)?) }, Err(e) => Err(e) } From ed2f8479880482108619af8b60cbed610450bca5 Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 15 Jul 2024 13:58:29 -0500 Subject: [PATCH 13/17] added impl for uuid lua stuff --- src/conversion.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/conversion.rs b/src/conversion.rs index 4b48447e..4af8457d 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -533,7 +533,10 @@ impl<'lua> FromLua<'lua> for uuid::Uuid { }); match string_result { Ok(string) => { - Ok(uuid::Uuid::parse_str(string.to_str()?)?) + match uuid::Uuid::parse_str(string.to_str()?) { + Ok(val) => Ok(val), + Err(e) => Err(e) + } }, Err(e) => Err(e) } From 277c6d87ed66f2fbd071d5f61d8184199d93dd9f Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 15 Jul 2024 14:02:36 -0500 Subject: [PATCH 14/17] added impl for uuid lua stuff --- src/conversion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversion.rs b/src/conversion.rs index 4af8457d..eb940335 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -535,7 +535,7 @@ impl<'lua> FromLua<'lua> for uuid::Uuid { Ok(string) => { match uuid::Uuid::parse_str(string.to_str()?) { Ok(val) => Ok(val), - Err(e) => Err(e) + Err(e) => Err(e.into()) } }, Err(e) => Err(e) From 72a524c3dbb8f9916d921e99e5b1366015d11e0d Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 15 Jul 2024 14:05:10 -0500 Subject: [PATCH 15/17] added impl for uuid lua stuff --- src/conversion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversion.rs b/src/conversion.rs index eb940335..700386f4 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -535,7 +535,7 @@ impl<'lua> FromLua<'lua> for uuid::Uuid { Ok(string) => { match uuid::Uuid::parse_str(string.to_str()?) { Ok(val) => Ok(val), - Err(e) => Err(e.into()) + Err(_) => Err(()) } }, Err(e) => Err(e) From 68904f5b618145f8f7178530deebd1602df87231 Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 15 Jul 2024 14:08:08 -0500 Subject: [PATCH 16/17] added impl for uuid lua stuff --- src/conversion.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/conversion.rs b/src/conversion.rs index 700386f4..413b9975 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -535,7 +535,11 @@ impl<'lua> FromLua<'lua> for uuid::Uuid { Ok(string) => { match uuid::Uuid::parse_str(string.to_str()?) { Ok(val) => Ok(val), - Err(_) => Err(()) + Err(_) => Err(Error::FromLuaConversionError { + from: "string", + to: "uuid::Uuid", + message: Some("failed to parse UUID".to_string()), + }) } }, Err(e) => Err(e) From 331db4a571998cce560a12ea4b0d83879ae11308 Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 15 Jul 2024 15:17:32 -0500 Subject: [PATCH 17/17] added impl for uuid lua stuff --- Cargo.toml | 4 +++ src/conversion.rs | 90 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index aca4ca21..9ee1587c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,8 @@ async = ["dep:futures-util"] send = [] serialize = ["dep:serde", "dep:erased-serde", "dep:serde-value"] uuid = ["dep:uuid", "dep:serde"] +time = ["dep:time"] +json = ["serialize", "serde_json"] macros = ["mlua_derive/macros"] unstable = [] @@ -52,9 +54,11 @@ num-traits = { version = "0.2.14" } rustc-hash = "2.0" futures-util = { version = "0.3", optional = true, default-features = false, features = ["std"] } serde = { version = "1.0", optional = true } +serde_json = { version = "1.0", optional = true} uuid = { version = "1.10.0", optional = true, features = ["v7", "serde"]} erased-serde = { version = "0.4", optional = true } serde-value = { version = "0.7", optional = true } +time = {version = "0.3.36", optional = true, features = ["parsing"]} parking_lot = { version = "0.12", optional = true } ffi = { package = "mlua-sys", version = "0.6.1", path = "mlua-sys" } diff --git a/src/conversion.rs b/src/conversion.rs index 413b9975..76b76e00 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -520,7 +520,91 @@ impl<'lua> FromLua<'lua> for LightUserData { } } -//#[cfg(feature = "uuid")] +#[cfg(feature = "time")] +impl<'lua> IntoLua<'lua> for time::OffsetDateTime { + fn into_lua(self, lua: &'lua Lua) -> Result> { + let datetime_str = self.format(&time::format_description::well_known::Rfc3339).map_err(|e| Error::RuntimeError(e.to_string()))?; + let lua_string = lua.create_string(&datetime_str)?; + Ok(Value::String(lua_string)) + } +} + +#[cfg(feature = "time")] +impl<'lua> FromLua<'lua> for time::OffsetDateTime { + fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { + match value { + Value::String(lua_string) => { + let datetime_str = lua_string.to_str()?; + time::OffsetDateTime::parse(datetime_str, &time::format_description::well_known::Rfc3339).map_err(|e| Error::FromLuaConversionError { + from: "string", + to: "time::OffsetDateTime", + message: Some(e.to_string()), + }) + }, + _ => Err(Error::FromLuaConversionError { + from: value.type_name(), + to: "time::OffsetDateTime", + message: Some("Expected a string".to_string()), + }), + } + } +} + +#[cfg(feature = "json")] +impl<'lua> IntoLua<'lua> for serde_json::Value { + #[inline] + fn into_lua(self, lua: &'lua Lua) -> Result> { + match self { + serde_json::Value::Null => Ok(Value::Nil), + serde_json::Value::Bool(b) => Ok(Value::Boolean(b)), + serde_json::Value::Number(n) => { + if let Some(i) = n.as_i64() { + Ok(Value::Integer(i)) + } else if let Some(f) = n.as_f64() { + Ok(Value::Number(f)) + } else { + Err(Error::FromLuaConversionError { + from: "number", + to: "Value", + message: Some("Invalid number".to_string()), + }) + } + }, + serde_json::Value::String(s) => { + let lua_string = lua.create_string(&s)?; + Ok(Value::String(lua_string)) + }, + serde_json::Value::Array(arr) => { + let lua_table = lua.create_table()?; + for (i, value) in arr.into_iter().enumerate() { + lua_table.set(i + 1, value.into_lua(lua)?)?; + } + Ok(Value::Table(lua_table)) + }, + serde_json::Value::Object(obj) => { + let lua_table = lua.create_table()?; + for (key, value) in obj { + lua_table.set(key, value.into_lua(lua)?)?; + } + Ok(Value::Table(lua_table)) + }, + } + } +} + +#[cfg(feature = "json")] +impl<'lua> FromLua<'lua> for serde_json::Value { + fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result { + let ty = value.type_name(); + serde_json::to_value(value).map_err(|e| Error::FromLuaConversionError { + from: ty, + to: "serde_json::Value", + message: Some(format!("{}", e)), + }) + } +} + +#[cfg(feature = "uuid")] impl<'lua> FromLua<'lua> for uuid::Uuid { #[inline] fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result { @@ -547,7 +631,7 @@ impl<'lua> FromLua<'lua> for uuid::Uuid { } } -//#[cfg(feature = "uuid")] +#[cfg(feature = "uuid")] impl<'lua> IntoLua<'lua> for uuid::Uuid { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> { @@ -556,7 +640,7 @@ impl<'lua> IntoLua<'lua> for uuid::Uuid { } } -//#[cfg(feature = "uuid")] +#[cfg(feature = "uuid")] impl<'lua> IntoLua<'lua> for &uuid::Uuid { #[inline] fn into_lua(self, lua: &'lua Lua) -> Result> {