diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e5c29c..ec24cb5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,16 +25,18 @@ jobs: - lua54,vendored - lua54,vendored,send - lua54,vendored,async - - lua54,vendored,derive + - lua54,vendored,macros + - lua54,vendored,macros,userdata-wrappers - lua54,vendored,send,async - - lua54,vendored,send,derive - - lua54,vendored,async,derive - - lua54,vendored,send,async,derive - # Full feature set including serialize and macros - - lua54,vendored,send,async,derive,serialize,macros + - lua54,vendored,send,macros + - lua54,vendored,async,macros + - lua54,vendored,send,async,macros + # Full feature set including serde and macros + - lua54,vendored,send,async,serde,macros # Luau feature combinations - luau,vendored - - luau,vendored,send,async,derive,serialize,macros + - luau,vendored,macros,userdata-wrappers + - luau,vendored,send,async,serde,macros steps: - uses: actions/checkout@v6 diff --git a/Cargo.toml b/Cargo.toml index c2a6735..6894dbc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,23 +11,23 @@ repository = "https://github.com/Tired-Fox/mlua-extras" keywords = ["lua", "mlua", "luajit", "luau", "scripting"] [package.metadata.docs.rs] -features = ["mlua", "lua54", "send", "async", "derive", "vendored"] +features = ["mlua", "lua54", "send", "async", "macros", "vendored"] [features] mlua = ["dep:mlua"] -lua54 = ["mlua/lua54", "mlua"] -lua53 = ["mlua/lua53", "mlua"] -lua52 = ["mlua/lua52", "mlua"] -lua51 = ["mlua/lua51", "mlua"] -luajit = ["mlua/luajit", "mlua"] -luau = ["mlua/luau", "mlua"] -vendored = ["mlua/vendored", "mlua"] -serialize = ["mlua/serialize", "mlua"] -macros = ["mlua/macros", "mlua"] -module = ["mlua/module", "mlua"] -send = ["mlua/send", "mlua"] -async = ["mlua/async", "mlua"] -derive = ["dep:mlua-extras-derive"] +lua54 = ["mlua", "mlua/lua54"] +lua53 = ["mlua", "mlua/lua53"] +lua52 = ["mlua", "mlua/lua52"] +lua51 = ["mlua", "mlua/lua51"] +luajit = ["mlua", "mlua/luajit"] +luau = ["mlua", "mlua/luau"] +vendored = ["mlua/vendored"] +serde = ["mlua/serde"] +macros = ["mlua/macros", "dep:mlua-extras-derive"] +module = ["mlua/module"] +send = ["mlua/send"] +async = ["mlua/async"] +userdata-wrappers = ["mlua/userdata-wrappers"] [dev-dependencies] serde = { version = "1.0.228", features = ["derive"] } @@ -42,7 +42,7 @@ strum = { version = "0.27.2", features = ["derive"], default-features = false } [[example]] name = "macros" -required-features = ["mlua", "derive"] +required-features = ["mlua", "macros"] [[example]] name = "enum_and_tuple" @@ -54,4 +54,4 @@ required-features = ["mlua"] [[example]] name = "typed" -required-features = ["mlua", "derive", "serialize"] +required-features = ["mlua", "macros", "serde"] diff --git a/mlua_extras_derive/Cargo.toml b/mlua_extras_derive/Cargo.toml index 6076f82..d5a3a43 100644 --- a/mlua_extras_derive/Cargo.toml +++ b/mlua_extras_derive/Cargo.toml @@ -11,7 +11,7 @@ description = "MLua extras macros" readme = "README.md" homepage = "https://github.com/Tired-Fox/mlua-extras" repository = "https://github.com/Tired-Fox/mlua-extras/tree/main/mlua_extras_derive" -keywords = ["lua", "types", "mlua", "macros", "derive"] +keywords = ["lua", "types", "mlua", "macros"] [dependencies] darling = "0.23.0" diff --git a/src/lib.rs b/src/lib.rs index 0aa21d9..bc1372a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ pub mod extras; #[cfg(feature="mlua")] pub use mlua; -#[cfg(feature="derive")] +#[cfg(feature="macros")] pub use mlua_extras_derive::{Typed, UserData, user_data_impl}; #[cfg(feature = "send")] @@ -21,10 +21,10 @@ pub trait MaybeSend {} #[cfg(not(feature = "send"))] impl MaybeSend for T {} -#[cfg(feature = "derive")] +#[cfg(feature = "macros")] #[doc(hidden)] pub trait __DefaultAutoMethods: Sized { fn __auto_add_methods(_m: &mut M) {} } -#[cfg(feature = "derive")] +#[cfg(feature = "macros")] impl __DefaultAutoMethods for T {} \ No newline at end of file diff --git a/src/typed/class/wrapped.rs b/src/typed/class/wrapped.rs index e27a395..2ce5bfa 100644 --- a/src/typed/class/wrapped.rs +++ b/src/typed/class/wrapped.rs @@ -265,7 +265,7 @@ impl<'ctx, T: UserData, U: UserDataMethods> TypedDataMethods for WrappedBu } #[cfg(test)] -#[cfg(all(feature = "async", feature = "derive"))] +#[cfg(all(feature = "async", feature = "macros"))] mod tests { use super::*; use crate as mlua_extras; diff --git a/src/typed/mod.rs b/src/typed/mod.rs index e6c0eb7..45a9c56 100644 --- a/src/typed/mod.rs +++ b/src/typed/mod.rs @@ -9,244 +9,15 @@ pub use class::{ }; use std::{ - borrow::Cow, - cell::{Cell, RefCell}, - collections::{BTreeMap, BTreeSet, HashMap, HashSet}, - marker::PhantomData, - rc::Rc, - sync::{Arc, Mutex}, + borrow::Cow, collections::{BTreeMap, BTreeSet, HashMap, HashSet}, marker::PhantomData }; +#[cfg(feature="userdata-wrappers")] +use std::{sync::{Arc, Mutex}, cell::{Cell, RefCell}, rc::Rc}; pub use function::{Param, Return, TypedFunction}; use mlua::{IntoLua, MetaMethod, Value, Variadic}; -/// Add a lua [`Type`] representation to a rust type -pub trait Typed { - /// Get the type representation - fn ty() -> Type; - - #[inline(always)] - fn implicit() -> impl IntoIterator { - [] - } - - /// Get the type as a function parameter - fn as_param() -> Type { - Self::ty() - } - - /// Get the type as a function return - fn as_return() -> Type { - Self::ty() - } -} - -#[macro_export] -macro_rules! join_types { - ($($ty:expr),+) => { - $crate::typed::Type::union([ - $($crate::typed::Type::from($ty),)+ - ]) - }; -} - -macro_rules! impl_static_typed { - { - $( - $($target: ty)|* - => $name: literal),* - $(,)? - } => { - $( - $( - impl Typed for $target { - fn ty() -> Type { - Type::named($name) - } - } - )* - )* - }; -} - -macro_rules! impl_static_typed_generic { - { - $( - $(for<$($lt: lifetime),+> $target: ty)|* - => $name: literal),* - $(,)? - } => { - $( - $( - impl<$($lt,)+> Typed for $target { - fn ty() -> Type { - Type::named($name) - } - } - )* - )* - }; -} - -impl_static_typed! { - mlua::LightUserData => "lightuserdata", - mlua::Error => "error", - String | &str => "string", - u8 | u16 | u32 | u64 | usize | u128 | i8 | i16 | i32 | i64 | isize | i128 => "integer", - f32 | f64 => "number", - bool => "boolean", - - mlua::Function => "fun()", - mlua::Table => "table", - mlua::AnyUserData => "userdata", - mlua::String => "string", - mlua::Thread => "thread", -} - -impl_static_typed_generic! { - for<'a> Cow<'a, str> => "string", -} - -impl Typed for mlua::Value { - fn ty() -> Type { - Type::Single("any".into()) - } -} - -impl Typed for Variadic { - /// ...type - fn ty() -> Type { - Type::any() - } -} - -/// {type} | nil -impl Typed for Option { - fn ty() -> Type { - T::ty() | Type::nil() - } - - fn as_param() -> Type { - T::as_param() | Type::nil() - } - - fn as_return() -> Type { - T::as_return() | Type::nil() - } -} - -impl From for Type { - fn from(value: T) -> Self { - Type::Single(value.into_lua_type_literal().into()) - } -} - -impl Typed for Arc { - fn ty() -> Type { - T::ty() - } -} - -impl Typed for Rc { - fn ty() -> Type { - T::ty() - } -} - -impl Typed for Cell { - fn ty() -> Type { - T::ty() - } -} - -impl Typed for RefCell { - fn ty() -> Type { - T::ty() - } -} - -impl Typed for Mutex { - fn ty() -> Type { - T::ty() - } -} - -impl Typed for PhantomData { - fn ty() -> Type { - T::ty() - } -} - -// Represents a lua tuple. -// -// With luaCATS tuples are represented with square brackets. -// -// # Example -// -// ```lua -// --- @type [string, integer, "literal"] -// ``` -impl From<[Type; N]> for Type { - fn from(value: [Type; N]) -> Self { - Type::Tuple(Vec::from(value)) - } -} - -// Array type - -impl Typed for [I; N] { - fn ty() -> Type { - Type::Array(I::ty().into()) - } -} - -impl Typed for Vec { - fn ty() -> Type { - Type::Array(I::ty().into()) - } -} - -impl Typed for &[I] { - fn ty() -> Type { - Type::Array(I::ty().into()) - } -} - -impl Typed for HashSet { - fn ty() -> Type { - Type::Array(I::ty().into()) - } -} - -impl Typed for BTreeSet { - fn ty() -> Type { - Type::Array(I::ty().into()) - } -} - -// Map type - -impl Typed for BTreeMap -where - K: Typed, - V: Typed, -{ - fn ty() -> Type { - Type::Map(K::ty().into(), V::ty().into()) - } -} - -impl Typed for HashMap -where - K: Typed, - V: Typed, -{ - fn ty() -> Type { - Type::Map(K::ty().into(), V::ty().into()) - } -} - /// Represents a lua table key /// /// Table keys can be either a string or an integer @@ -644,29 +415,380 @@ impl_type_literal! { } impl_type_literal! {bool} -/// Typed information for a lua [`MultiValue`][mlua::MultiValue] -pub trait TypedMultiValue { - /// Gets the types contained in this collection. - /// Order *IS* important. - fn get_types() -> Vec { - Self::get_types_as_params() - .into_iter() - .map(|v| v.ty) - .collect::>() +/// Add a lua [`Type`] representation to a rust type +pub trait Typed { + /// Get the type representation + fn ty() -> Type; + + #[inline(always)] + fn implicit() -> impl IntoIterator { + [] } - fn get_types_as_returns() -> Vec { - Vec::new() + /// Get the type as a function parameter + fn as_param() -> Type { + Self::ty() } - /// Gets the type representations as used for function parameters - fn get_types_as_params() -> Vec { - Vec::new() + /// Get the type as a function return + fn as_return() -> Type { + Self::ty() } } -macro_rules! impl_typed_multi_value { - () => { +#[macro_export] +macro_rules! join_types { + ($($ty:expr),+) => { + $crate::typed::Type::union([ + $($crate::typed::Type::from($ty),)+ + ]) + }; +} + +macro_rules! impl_static_typed { + { + $( + $($target: ty)|* + => $name: literal),* + $(,)? + } => { + $( + $( + impl Typed for $target { + fn ty() -> Type { + Type::named($name) + } + } + )* + )* + }; +} + +macro_rules! impl_static_typed_generic { + { + $( + $(for<$($lt: lifetime),+> $target: ty)|* + => $name: literal),* + $(,)? + } => { + $( + $( + impl<$($lt,)+> Typed for $target { + fn ty() -> Type { + Type::named($name) + } + } + )* + )* + }; +} + +impl_static_typed! { + mlua::LightUserData => "lightuserdata", + mlua::Error => "error", + String | &str => "string", + u8 | u16 | u32 | u64 | usize | u128 | i8 | i16 | i32 | i64 | isize | i128 => "integer", + f32 | f64 => "number", + bool => "boolean", + + mlua::Function => "fun()", + mlua::Table => "table", + mlua::AnyUserData => "userdata", + mlua::String => "string", + mlua::Thread => "thread", +} + +impl_static_typed_generic! { + for<'a> Cow<'a, str> => "string", +} + +impl Typed for mlua::Value { + fn ty() -> Type { + Type::Single("any".into()) + } +} + +impl Typed for Variadic { + /// ...type + fn ty() -> Type { + Type::any() + } +} + +impl From for Type { + fn from(value: T) -> Self { + Type::Single(value.into_lua_type_literal().into()) + } +} + +/// {type} | nil +impl Typed for Option { + fn ty() -> Type { + T::ty() | Type::nil() + } + + fn as_param() -> Type { + T::as_param() | Type::nil() + } + + fn as_return() -> Type { + T::as_return() | Type::nil() + } +} + +impl Typed for Box { + fn ty() -> Type { + T::ty() + } + + fn as_param() -> Type { + T::as_param() + } + + fn as_return() -> Type { + T::as_return() + } +} + +impl Typed for PhantomData { + fn ty() -> Type { + T::ty() + } + + fn as_param() -> Type { + T::as_param() + } + + fn as_return() -> Type { + T::as_return() + } +} + +// Represents a lua tuple. +// +// With luaCATS tuples are represented with square brackets. +// +// # Example +// +// ```lua +// --- @type [string, integer, "literal"] +// ``` +impl From<[Type; N]> for Type { + fn from(value: [Type; N]) -> Self { + Type::Tuple(Vec::from(value)) + } +} + +// Array type + +impl Typed for [I; N] { + fn ty() -> Type { + Type::Array(I::ty().into()) + } + + fn as_param() -> Type { + Type::Array(I::as_param().into()) + } + + fn as_return() -> Type { + Type::Array(I::as_return().into()) + } +} + +impl Typed for Vec { + fn ty() -> Type { + Type::Array(I::ty().into()) + } + + fn as_param() -> Type { + Type::Array(I::as_param().into()) + } + + fn as_return() -> Type { + Type::Array(I::as_return().into()) + } +} + +impl Typed for &[I] { + fn ty() -> Type { + Type::Array(I::ty().into()) + } + + fn as_param() -> Type { + Type::Array(I::as_param().into()) + } + + fn as_return() -> Type { + Type::Array(I::as_return().into()) + } +} + +impl Typed for HashSet { + fn ty() -> Type { + Type::Array(I::ty().into()) + } + + fn as_param() -> Type { + Type::Array(I::as_param().into()) + } + + fn as_return() -> Type { + Type::Array(I::as_return().into()) + } +} + +impl Typed for BTreeSet { + fn ty() -> Type { + Type::Array(I::ty().into()) + } + + fn as_param() -> Type { + Type::Array(I::as_param().into()) + } + + fn as_return() -> Type { + Type::Array(I::as_return().into()) + } +} + +// Map type + +impl Typed for BTreeMap +where + K: Typed, + V: Typed, +{ + fn ty() -> Type { + Type::Map(K::ty().into(), V::ty().into()) + } + + fn as_param() -> Type { + Type::Map(K::as_param().into(), V::as_param().into()) + } + + fn as_return() -> Type { + Type::Map(K::as_return().into(), V::as_return().into()) + } +} + +impl Typed for HashMap +where + K: Typed, + V: Typed, +{ + fn ty() -> Type { + Type::Map(K::ty().into(), V::ty().into()) + } + + fn as_param() -> Type { + Type::Map(K::as_param().into(), V::as_param().into()) + } + + fn as_return() -> Type { + Type::Map(K::as_return().into(), V::as_return().into()) + } +} + +// External Types + +#[cfg(feature="userdata-wrappers")] +impl Typed for Arc { + fn ty() -> Type { + T::ty() + } + + fn as_param() -> Type { + T::as_param() + } + + fn as_return() -> Type { + T::as_return() + } +} + +#[cfg(feature="userdata-wrappers")] +impl Typed for Rc { + fn ty() -> Type { + T::ty() + } + + fn as_param() -> Type { + T::as_param() + } + + fn as_return() -> Type { + T::as_return() + } +} + +#[cfg(feature="userdata-wrappers")] +impl Typed for Cell { + fn ty() -> Type { + T::ty() + } + + fn as_param() -> Type { + T::as_param() + } + + fn as_return() -> Type { + T::as_return() + } +} + +#[cfg(feature="userdata-wrappers")] +impl Typed for RefCell { + fn ty() -> Type { + T::ty() + } + + fn as_param() -> Type { + T::as_param() + } + + fn as_return() -> Type { + T::as_return() + } +} + +#[cfg(feature="userdata-wrappers")] +impl Typed for Mutex { + fn ty() -> Type { + T::ty() + } + + fn as_param() -> Type { + T::as_param() + } + + fn as_return() -> Type { + T::as_return() + } +} + +/// Typed information for a lua [`MultiValue`][mlua::MultiValue] +pub trait TypedMultiValue { + /// Gets the types contained in this collection. + /// Order *IS* important. + fn get_types() -> Vec { + Self::get_types_as_params() + .into_iter() + .map(|v| v.ty) + .collect::>() + } + + fn get_types_as_returns() -> Vec { + Vec::new() + } + + /// Gets the type representations as used for function parameters + fn get_types_as_params() -> Vec { + Vec::new() + } +} + +macro_rules! impl_typed_multi_value { + () => { impl TypedMultiValue for () {} }; ($($name:ident) +) => { @@ -829,4 +951,4 @@ impl IntoDocComment for Option> { fn into_doc_comment(self) -> Option> { self.and_then(|v| (!v.trim().is_empty()).then_some(v)) } -} \ No newline at end of file +} diff --git a/tests/recursive.rs b/tests/recursive.rs index 85292bf..b8e1b33 100644 --- a/tests/recursive.rs +++ b/tests/recursive.rs @@ -1,4 +1,4 @@ -#![cfg(all(feature = "mlua", feature = "derive"))] +#![cfg(all(feature = "mlua", feature = "macros"))] use mlua::{FromLua, MetaMethod, UserData, Value}; use mlua_extras::{ @@ -64,6 +64,29 @@ impl TypedUserData for TestOption { }) }, ); + + #[cfg(feature="userdata-wrappers")] + methods.add_function( + "func_returns_arc_self", + |_, ()| -> mlua::Result> { Ok(Default::default()) }, + ); + #[cfg(feature="userdata-wrappers")] + methods.add_function( + "func_returns_arc_mutex_self", + |_, ()| -> mlua::Result>> { Ok(Default::default()) }, + ); + + #[cfg(feature="userdata-wrappers")] + methods.add_function( + "func_returns_rc_refcell_self", + |_, ()| -> mlua::Result> { Ok(Default::default()) }, + ); + #[cfg(feature="userdata-wrappers")] + methods.add_function( + "func_returns_rc_refcell_self", + |_, ()| -> mlua::Result>> { Ok(Default::default()) }, + ); + methods.add_method("clone", |_, this, ()| Ok(this.clone())); methods.add_method( diff --git a/tests/user_data.rs b/tests/user_data.rs index 28ab31c..97c09ed 100644 --- a/tests/user_data.rs +++ b/tests/user_data.rs @@ -1,4 +1,4 @@ -#![cfg(all(feature = "mlua", feature = "derive"))] +#![cfg(all(feature = "mlua", feature = "macros"))] use mlua::{AnyUserData, FromLua}; use mlua_extras::{