From 4a8e481bfc6152e6db20c8714f25ac7992dc7001 Mon Sep 17 00:00:00 2001 From: makspll Date: Mon, 10 Feb 2025 16:28:23 +0000 Subject: [PATCH 1/3] feat: add `TypeKind` to function meta, and refactor --- .../src/bindings/function/mod.rs | 2 +- .../src/docgen/info.rs | 86 ++++++++++--------- 2 files changed, 46 insertions(+), 42 deletions(-) diff --git a/crates/bevy_mod_scripting_core/src/bindings/function/mod.rs b/crates/bevy_mod_scripting_core/src/bindings/function/mod.rs index 1f4eb9106a..7a562c7ef3 100644 --- a/crates/bevy_mod_scripting_core/src/bindings/function/mod.rs +++ b/crates/bevy_mod_scripting_core/src/bindings/function/mod.rs @@ -66,7 +66,7 @@ mod test { assert_eq!(test_fn.info.arg_info[1].name, Some("_arg1".into())); assert_eq!( - test_fn.info.return_info.type_id, + test_fn.info.return_info.as_ref().unwrap().type_id, std::any::TypeId::of::<()>() ); } diff --git a/crates/bevy_mod_scripting_core/src/docgen/info.rs b/crates/bevy_mod_scripting_core/src/docgen/info.rs index 82f4ffaea1..ece29a2ee8 100644 --- a/crates/bevy_mod_scripting_core/src/docgen/info.rs +++ b/crates/bevy_mod_scripting_core/src/docgen/info.rs @@ -2,8 +2,9 @@ use bevy::reflect::Reflect; -use crate::bindings::function::arg_meta::ArgMeta; +use crate::bindings::function::from::{Mut, Val}; use crate::bindings::function::namespace::Namespace; +use crate::bindings::function::{arg_meta::ArgMeta, from::Ref}; use std::{any::TypeId, borrow::Cow}; /// for things you can call and provide some introspection capability. @@ -22,7 +23,7 @@ pub struct FunctionInfo { /// Information about the arguments of the function. pub arg_info: Vec, /// Information about the return value of the function. - pub return_info: FunctionReturnInfo, + pub return_info: Option, /// Documentation for the function. pub docs: Option>, } @@ -40,7 +41,7 @@ impl FunctionInfo { name: Cow::Borrowed(""), namespace: Namespace::Global, arg_info: Vec::new(), - return_info: FunctionReturnInfo::new(), + return_info: None, docs: None, } } @@ -51,7 +52,7 @@ impl FunctionInfo { name, namespace, arg_info: Vec::new(), - return_info: FunctionReturnInfo::new(), + return_info: None, docs: None, } } @@ -62,14 +63,14 @@ impl FunctionInfo { name, arg_index: self.arg_info.len(), type_id: TypeId::of::(), - docs: None, + type_kind: TypeKind::new_for::(), }); self } /// Add a return value to the function info. - pub fn add_return(mut self, return_info: FunctionReturnInfo) -> Self { - self.return_info = return_info; + pub fn add_return(mut self) -> Self { + self.return_info = Some(FunctionReturnInfo::new_for::()); self } @@ -94,6 +95,35 @@ impl FunctionInfo { } } +/// The kind of type being used as a return value or argument in a script function. +#[derive(Debug, Clone, PartialEq, Reflect)] +pub enum TypeKind { + /// A `Ref` wrapped type + Ref, + /// A `Mut` wrapped type + Mut, + /// A `Val` wrapped type + Val, + /// Any other type, such as a primtive or something which implements `IntoScript` or `FromScript` directly + Primitive, +} + +impl TypeKind { + /// Create a new type kind for a specific type. + pub fn new_for() -> Self { + let type_id = TypeId::of::(); + if std::any::TypeId::of::>() == type_id { + Self::Ref + } else if std::any::TypeId::of::>() == type_id { + Self::Mut + } else if std::any::TypeId::of::>() == type_id { + Self::Val + } else { + Self::Primitive + } + } +} + #[derive(Debug, Clone, PartialEq, Reflect)] /// Information about a function argument. pub struct FunctionArgInfo { @@ -103,32 +133,16 @@ pub struct FunctionArgInfo { pub arg_index: usize, /// The type of the argument. pub type_id: TypeId, - /// Documentation for the argument. - pub docs: Option>, + /// The kind of type being used as an argument. + pub type_kind: TypeKind, } impl FunctionArgInfo { - /// Create a new function argument info with default values. - pub fn new(arg_index: usize, type_id: TypeId) -> Self { - Self { - name: None, - arg_index, - type_id, - docs: None, - } - } - /// Create a new function argument info with a name. pub fn with_name(mut self, name: Cow<'static, str>) -> Self { self.name = Some(name); self } - - /// Add documentation to the function argument info. - pub fn with_docs(mut self, docs: Cow<'static, str>) -> Self { - self.docs = Some(docs); - self - } } #[derive(Debug, Clone, PartialEq, Reflect)] @@ -136,26 +150,16 @@ impl FunctionArgInfo { pub struct FunctionReturnInfo { /// The type of the return value. pub type_id: TypeId, -} - -impl Default for FunctionReturnInfo { - fn default() -> Self { - Self::new() - } + /// The kind of type being used as a return value. + pub type_kind: TypeKind, } impl FunctionReturnInfo { - /// Create a new function return info with default values. - pub fn new() -> Self { - Self { - type_id: TypeId::of::<()>(), - } - } - /// Create a new function return info for a specific type. pub fn new_for() -> Self { Self { type_id: TypeId::of::(), + type_kind: TypeKind::new_for::(), } } } @@ -174,7 +178,7 @@ macro_rules! impl_documentable { $( info = info.add_arg::<$param>(None); )* - info.add_return(FunctionReturnInfo::new_for::()) + info.add_return::() } } }; @@ -198,7 +202,7 @@ mod test { assert_eq!(info.name, "test_fn"); assert_eq!(info.namespace, Namespace::Global); assert_eq!(info.arg_info.len(), 2); - assert_eq!(info.return_info.type_id, TypeId::of::()); + assert_eq!(info.return_info.unwrap().type_id, TypeId::of::()); assert_eq!(info.arg_info[0].type_id, TypeId::of::()); assert_eq!(info.arg_info[1].type_id, TypeId::of::()); @@ -212,7 +216,7 @@ mod test { assert_eq!(info.name, "test_fn"); assert_eq!(info.namespace, Namespace::Global); assert_eq!(info.arg_info.len(), 2); - assert_eq!(info.return_info.type_id, TypeId::of::>()); + assert_eq!(info.return_info.unwrap().type_id, TypeId::of::>()); assert_eq!(info.arg_info[0].type_id, TypeId::of::>()); assert_eq!(info.arg_info[1].type_id, TypeId::of::>()); From bfb381c818ac6b30409660184e980429dcf9a262 Mon Sep 17 00:00:00 2001 From: makspll Date: Mon, 10 Feb 2025 21:05:32 +0000 Subject: [PATCH 2/3] add `TypedThrough` abstraction --- .../src/bindings/function/arg_meta.rs | 43 ++- .../src/bindings/function/mod.rs | 37 +-- .../src/bindings/function/script_function.rs | 24 +- .../src/docgen/info.rs | 81 +++--- .../bevy_mod_scripting_core/src/docgen/mod.rs | 1 + .../src/docgen/typed_through.rs | 262 ++++++++++++++++++ 6 files changed, 361 insertions(+), 87 deletions(-) create mode 100644 crates/bevy_mod_scripting_core/src/docgen/typed_through.rs diff --git a/crates/bevy_mod_scripting_core/src/bindings/function/arg_meta.rs b/crates/bevy_mod_scripting_core/src/bindings/function/arg_meta.rs index a8ca08cee4..5fdec4ade0 100644 --- a/crates/bevy_mod_scripting_core/src/bindings/function/arg_meta.rs +++ b/crates/bevy_mod_scripting_core/src/bindings/function/arg_meta.rs @@ -2,7 +2,10 @@ use std::{ffi::OsString, path::PathBuf}; -use crate::bindings::{script_value::ScriptValue, ReflectReference}; +use crate::{ + bindings::{script_value::ScriptValue, ReflectReference}, + docgen::typed_through::TypedThrough, +}; use super::{ from::{FromScript, Mut, Ref, Val}, @@ -15,10 +18,18 @@ use super::{ pub trait ScriptArgument: ArgMeta + FromScript + GetTypeDependencies {} impl ScriptArgument for T {} +/// Marker trait for types that can be used as arguments to a script function. And contain type information. +pub trait TypedScriptArgument: TypedThrough + ScriptArgument {} +impl TypedScriptArgument for T {} + /// Marker trait for types that can be used as return values from a script function. pub trait ScriptReturn: IntoScript + GetTypeDependencies {} impl ScriptReturn for T {} +/// Marker trait for types that can be used as return values from a script function. And contain type information. +pub trait TypedScriptReturn: TypedThrough + ScriptReturn {} +impl TypedScriptReturn for T {} + /// Describes an argument to a script function. Provides necessary information for the function to handle dispatch. pub trait ArgMeta { /// The default value for the argument. Used when the argument is not provided. @@ -37,13 +48,29 @@ macro_rules! impl_arg_info { }; } -impl_arg_info!(bool, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32, f64, usize, isize); - -impl_arg_info!(String, PathBuf, OsString); - -impl_arg_info!(char); - -impl_arg_info!(ReflectReference); +impl_arg_info!( + bool, + i8, + i16, + i32, + i64, + i128, + u8, + u16, + u32, + u64, + u128, + f32, + f64, + usize, + isize, + String, + PathBuf, + OsString, + char, + ReflectReference, + &'static str +); impl ArgMeta for Val {} impl ArgMeta for Ref<'_, T> {} diff --git a/crates/bevy_mod_scripting_core/src/bindings/function/mod.rs b/crates/bevy_mod_scripting_core/src/bindings/function/mod.rs index 7a562c7ef3..6c5e08e121 100644 --- a/crates/bevy_mod_scripting_core/src/bindings/function/mod.rs +++ b/crates/bevy_mod_scripting_core/src/bindings/function/mod.rs @@ -16,15 +16,18 @@ mod test { use bevy_mod_scripting_derive::script_bindings; use crate::{ - bindings::function::{ - from::{Ref, Val}, - namespace::IntoNamespace, - script_function::AppScriptFunctionRegistry, + bindings::{ + function::{ + from::{Ref, Val}, + namespace::IntoNamespace, + script_function::AppScriptFunctionRegistry, + }, + script_value::ScriptValue, }, - error::InteropError, + docgen::typed_through::TypedThrough, }; - use super::arg_meta::{ScriptArgument, ScriptReturn}; + use super::arg_meta::{ScriptArgument, ScriptReturn, TypedScriptArgument, TypedScriptReturn}; #[test] fn test_macro_generates_correct_registrator_function() { @@ -71,9 +74,9 @@ mod test { ); } - fn test_is_valid_return() {} - fn test_is_valid_arg() {} - fn test_is_valid_arg_and_return() {} + fn test_is_valid_return() {} + fn test_is_valid_arg() {} + fn test_is_valid_arg_and_return() {} #[test] fn primitives_are_valid_args() { @@ -92,6 +95,7 @@ mod test { test_is_valid_arg_and_return::(); test_is_valid_arg_and_return::(); test_is_valid_arg_and_return::(); + test_is_valid_arg_and_return::(); } #[test] @@ -100,6 +104,7 @@ mod test { test_is_valid_arg_and_return::(); test_is_valid_arg_and_return::(); test_is_valid_arg_and_return::(); + test_is_valid_return::<&'static str>(); } #[test] @@ -107,7 +112,7 @@ mod test { fn test_val() where T: ScriptArgument + ScriptReturn, - T: GetTypeRegistration + FromReflect, + T: GetTypeRegistration + FromReflect + Typed, { test_is_valid_arg_and_return::>(); } @@ -128,12 +133,10 @@ mod test { test_is_valid_arg::>(); } - test_is_valid_return::(); - fn test_array() where T: ScriptArgument + ScriptReturn, - T: GetTypeRegistration + FromReflect + Typed, + T: GetTypeRegistration + FromReflect + TypedThrough + Typed, for<'a> T::This<'a>: Into, { test_is_valid_arg_and_return::<[T; N]>(); @@ -142,7 +145,7 @@ mod test { fn test_tuple() where T: ScriptArgument + ScriptReturn, - T: GetTypeRegistration + FromReflect + Typed, + T: GetTypeRegistration + FromReflect + TypedThrough + Typed, for<'a> T::This<'a>: Into, { test_is_valid_arg_and_return::<()>(); @@ -154,7 +157,7 @@ mod test { fn test_option() where T: ScriptArgument + ScriptReturn, - T: GetTypeRegistration + FromReflect + Typed, + T: GetTypeRegistration + FromReflect + Typed + TypedThrough, for<'a> T::This<'a>: Into, { test_is_valid_arg_and_return::>(); @@ -163,7 +166,7 @@ mod test { fn test_vec() where T: ScriptArgument + ScriptReturn, - T: GetTypeRegistration + FromReflect + Typed, + T: GetTypeRegistration + FromReflect + Typed + TypedThrough, for<'a> T::This<'a>: Into, { test_is_valid_arg_and_return::>(); @@ -172,7 +175,7 @@ mod test { fn test_hashmap() where V: ScriptArgument + ScriptReturn, - V: GetTypeRegistration + FromReflect + Typed, + V: GetTypeRegistration + FromReflect + Typed + TypedThrough, for<'a> V::This<'a>: Into, { test_is_valid_arg_and_return::>(); diff --git a/crates/bevy_mod_scripting_core/src/bindings/function/script_function.rs b/crates/bevy_mod_scripting_core/src/bindings/function/script_function.rs index c2b1dd559c..4c9e42d61b 100644 --- a/crates/bevy_mod_scripting_core/src/bindings/function/script_function.rs +++ b/crates/bevy_mod_scripting_core/src/bindings/function/script_function.rs @@ -73,12 +73,6 @@ pub struct DynamicScriptFunction { >, } -impl PartialEq for DynamicScriptFunction { - fn eq(&self, other: &Self) -> bool { - self.info == other.info - } -} - #[derive(Clone, Reflect)] #[reflect(opaque)] /// A dynamic mutable script function. @@ -96,12 +90,6 @@ pub struct DynamicScriptFunctionMut { >, } -impl PartialEq for DynamicScriptFunctionMut { - fn eq(&self, other: &Self) -> bool { - self.info == other.info - } -} - impl DynamicScriptFunction { /// Call the function with the given arguments and caller context. /// @@ -215,6 +203,18 @@ impl DynamicScriptFunctionMut { } } +impl PartialEq for DynamicScriptFunction { + fn eq(&self, other: &Self) -> bool { + std::ptr::addr_eq(self as *const Self, other as *const Self) + } +} + +impl PartialEq for DynamicScriptFunctionMut { + fn eq(&self, other: &Self) -> bool { + std::ptr::addr_eq(self as *const Self, other as *const Self) + } +} + impl std::fmt::Debug for DynamicScriptFunction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("DynamicScriptFunction") diff --git a/crates/bevy_mod_scripting_core/src/docgen/info.rs b/crates/bevy_mod_scripting_core/src/docgen/info.rs index ece29a2ee8..bfc582cca1 100644 --- a/crates/bevy_mod_scripting_core/src/docgen/info.rs +++ b/crates/bevy_mod_scripting_core/src/docgen/info.rs @@ -1,19 +1,19 @@ //! Information about functions and their arguments. -use bevy::reflect::Reflect; - -use crate::bindings::function::from::{Mut, Val}; +use crate::bindings::function::arg_meta::ArgMeta; use crate::bindings::function::namespace::Namespace; -use crate::bindings::function::{arg_meta::ArgMeta, from::Ref}; +use bevy::reflect::Reflect; use std::{any::TypeId, borrow::Cow}; +use super::typed_through::{ThroughTypeInfo, TypedThrough}; + /// for things you can call and provide some introspection capability. pub trait GetFunctionInfo { /// Get the function info for the function. fn get_function_info(&self, name: Cow<'static, str>, namespace: Namespace) -> FunctionInfo; } -#[derive(Debug, Clone, PartialEq, Reflect)] +#[derive(Debug, Clone, Reflect)] /// Information about a function. pub struct FunctionInfo { /// The name of the function. @@ -58,18 +58,17 @@ impl FunctionInfo { } /// Add an argument to the function info. - pub fn add_arg(mut self, name: Option>) -> Self { - self.arg_info.push(FunctionArgInfo { - name, - arg_index: self.arg_info.len(), - type_id: TypeId::of::(), - type_kind: TypeKind::new_for::(), - }); + pub fn add_arg( + mut self, + name: Option>, + ) -> Self { + self.arg_info + .push(FunctionArgInfo::for_type::(name, self.arg_info.len())); self } /// Add a return value to the function info. - pub fn add_return(mut self) -> Self { + pub fn add_return(mut self) -> Self { self.return_info = Some(FunctionReturnInfo::new_for::()); self } @@ -95,36 +94,7 @@ impl FunctionInfo { } } -/// The kind of type being used as a return value or argument in a script function. -#[derive(Debug, Clone, PartialEq, Reflect)] -pub enum TypeKind { - /// A `Ref` wrapped type - Ref, - /// A `Mut` wrapped type - Mut, - /// A `Val` wrapped type - Val, - /// Any other type, such as a primtive or something which implements `IntoScript` or `FromScript` directly - Primitive, -} - -impl TypeKind { - /// Create a new type kind for a specific type. - pub fn new_for() -> Self { - let type_id = TypeId::of::(); - if std::any::TypeId::of::>() == type_id { - Self::Ref - } else if std::any::TypeId::of::>() == type_id { - Self::Mut - } else if std::any::TypeId::of::>() == type_id { - Self::Val - } else { - Self::Primitive - } - } -} - -#[derive(Debug, Clone, PartialEq, Reflect)] +#[derive(Debug, Clone, Reflect)] /// Information about a function argument. pub struct FunctionArgInfo { /// The name of the argument. @@ -133,8 +103,9 @@ pub struct FunctionArgInfo { pub arg_index: usize, /// The type of the argument. pub type_id: TypeId, - /// The kind of type being used as an argument. - pub type_kind: TypeKind, + /// The type information of the argument. + #[reflect(ignore)] + pub type_info: Option, } impl FunctionArgInfo { @@ -143,6 +114,19 @@ impl FunctionArgInfo { self.name = Some(name); self } + + /// Create a new function argument info for a specific type. + pub fn for_type( + name: Option>>, + arg_index: usize, + ) -> Self { + Self { + name: name.map(Into::into), + arg_index, + type_id: TypeId::of::(), + type_info: Some(T::through_type_info()), + } + } } #[derive(Debug, Clone, PartialEq, Reflect)] @@ -150,8 +134,6 @@ impl FunctionArgInfo { pub struct FunctionReturnInfo { /// The type of the return value. pub type_id: TypeId, - /// The kind of type being used as a return value. - pub type_kind: TypeKind, } impl FunctionReturnInfo { @@ -159,7 +141,6 @@ impl FunctionReturnInfo { pub fn new_for() -> Self { Self { type_id: TypeId::of::(), - type_kind: TypeKind::new_for::(), } } } @@ -169,8 +150,8 @@ macro_rules! impl_documentable { impl<$($param,)* F, O> GetFunctionInfo O> for F where F: Fn($($param),*) -> O, - $($param: ArgMeta + 'static,)* - O: 'static + $($param: ArgMeta + TypedThrough + 'static,)* + O: TypedThrough + 'static { fn get_function_info(&self, name: Cow<'static, str>, namespace: Namespace) -> FunctionInfo { #[allow(unused_mut)] diff --git a/crates/bevy_mod_scripting_core/src/docgen/mod.rs b/crates/bevy_mod_scripting_core/src/docgen/mod.rs index 38cc7be64f..e74e969692 100644 --- a/crates/bevy_mod_scripting_core/src/docgen/mod.rs +++ b/crates/bevy_mod_scripting_core/src/docgen/mod.rs @@ -1,2 +1,3 @@ //! Documentation generation for scripting languages. pub mod info; +pub mod typed_through; diff --git a/crates/bevy_mod_scripting_core/src/docgen/typed_through.rs b/crates/bevy_mod_scripting_core/src/docgen/typed_through.rs new file mode 100644 index 0000000000..3efb4f1155 --- /dev/null +++ b/crates/bevy_mod_scripting_core/src/docgen/typed_through.rs @@ -0,0 +1,262 @@ +//! Defines a set of traits which destruture [`bevy::reflect::TypeInfo`] and implement a light weight wrapper around it, to allow types +//! which normally can't implement [`bevy::reflect::Typed`] to be used in a reflection context. + +use std::{any::TypeId, ffi::OsString, path::PathBuf}; + +use bevy::reflect::{TypeInfo, Typed}; + +use crate::{ + bindings::{ + function::{ + from::{Mut, Ref, Val}, + script_function::{ + DynamicScriptFunction, DynamicScriptFunctionMut, FunctionCallContext, + }, + }, + script_value::ScriptValue, + ReflectReference, + }, + error::InteropError, +}; + +/// All Through types follow one rule: +/// - A through type can not contain a nested through type. It must always contain a fully typed inner type. +/// +/// This means that: +/// - `Ref>` is not allowed, but `Ref` is. +/// +/// i.e. `Ref`, `Mut` and `Val` wrappers are `leaf` types, and can not contain other `leaf` types. +/// +/// This is to keep the implementations of this trait simple, and to ultimately depend on the `TypeInfo` trait for the actual type information. +#[derive(Debug, Clone)] +pub enum ThroughTypeInfo { + /// A wrapper around a typed type, which itself is not a `Typed` type. + UntypedWrapper { + /// The type information of the inner type. + through_type: &'static TypeInfo, + /// The type id of the wrapper type. + wrapper_type_id: TypeId, + /// The name of the wrapper type. + wrapper_name: &'static str, + }, + /// A wrapper around a through typed type, which itself is also a `Typed` type. + TypedWrapper(TypedWrapperKind), + /// an actual type info + TypeInfo(&'static TypeInfo), +} + +/// The kind of typed wrapper. +#[derive(Debug, Clone)] +pub enum TypedWrapperKind { + /// Wraps a `Vec` of a through typed type. + Vec(Box), + /// Wraps a `HashMap` of a through typed type. + HashMap(Box, Box), + /// Wraps a `Result` of a through typed type. + Array(Box, usize), + /// Wraps an `Option` of a through typed type. + Option(Box), + /// Wraps a `Result` of a through typed type. + InteropResult(Box), + /// Wraps a tuple of through typed types. + Tuple(Vec), +} + +/// A trait for types that can be converted to a [`ThroughTypeInfo`]. +pub trait TypedThrough { + /// Get the [`ThroughTypeInfo`] for the type. + fn through_type_info() -> ThroughTypeInfo; +} + +impl TypedThrough for Ref<'_, T> { + fn through_type_info() -> ThroughTypeInfo { + ThroughTypeInfo::UntypedWrapper { + through_type: T::type_info(), + wrapper_type_id: TypeId::of::>(), + wrapper_name: "Ref", + } + } +} + +impl TypedThrough for Mut<'_, T> { + fn through_type_info() -> ThroughTypeInfo { + ThroughTypeInfo::UntypedWrapper { + through_type: T::type_info(), + wrapper_type_id: TypeId::of::>(), + wrapper_name: "Mut", + } + } +} + +impl TypedThrough for Val { + fn through_type_info() -> ThroughTypeInfo { + ThroughTypeInfo::UntypedWrapper { + through_type: T::type_info(), + wrapper_type_id: TypeId::of::>(), + wrapper_name: "Val", + } + } +} + +impl TypedThrough for Vec { + fn through_type_info() -> ThroughTypeInfo { + ThroughTypeInfo::TypedWrapper(TypedWrapperKind::Vec(Box::new(T::through_type_info()))) + } +} + +impl TypedThrough for std::collections::HashMap { + fn through_type_info() -> ThroughTypeInfo { + ThroughTypeInfo::TypedWrapper(TypedWrapperKind::HashMap( + Box::new(K::through_type_info()), + Box::new(V::through_type_info()), + )) + } +} + +impl TypedThrough for Result { + fn through_type_info() -> ThroughTypeInfo { + ThroughTypeInfo::TypedWrapper(TypedWrapperKind::InteropResult(Box::new( + T::through_type_info(), + ))) + } +} + +impl TypedThrough for [T; N] { + fn through_type_info() -> ThroughTypeInfo { + ThroughTypeInfo::TypedWrapper(TypedWrapperKind::Array(Box::new(T::through_type_info()), N)) + } +} + +impl TypedThrough for Option { + fn through_type_info() -> ThroughTypeInfo { + ThroughTypeInfo::TypedWrapper(TypedWrapperKind::Option(Box::new(T::through_type_info()))) + } +} + +macro_rules! impl_through_typed { + ($($ty:ty),*) => { + $( + impl $crate::docgen::typed_through::TypedThrough for $ty { + fn through_type_info() -> $crate::docgen::typed_through::ThroughTypeInfo { + $crate::docgen::typed_through::ThroughTypeInfo::TypeInfo(<$ty as bevy::reflect::Typed>::type_info()) + } + } + )* + }; +} + +impl_through_typed!( + FunctionCallContext, + ReflectReference, + DynamicScriptFunctionMut, + DynamicScriptFunction, + ScriptValue, + bool, + i8, + i16, + i32, + i64, + i128, + u8, + u16, + u32, + u64, + u128, + f32, + f64, + usize, + isize, + String, + PathBuf, + OsString, + char, + &'static str +); + +macro_rules! impl_through_typed_tuple { + ($($ty:ident),*) => { + impl<$($ty: TypedThrough),*> TypedThrough for ($($ty,)*) { + fn through_type_info() -> ThroughTypeInfo { + ThroughTypeInfo::TypedWrapper(TypedWrapperKind::Tuple(vec![$($ty::through_type_info()),*])) + } + } + }; +} + +bevy::utils::all_tuples!(impl_through_typed_tuple, 0, 13, T); + +#[cfg(test)] +mod test { + use super::*; + + fn assert_type_info_is_through() { + let type_info = T::type_info(); + let through_type_info = T::through_type_info(); + + match through_type_info { + ThroughTypeInfo::TypeInfo(info) => { + assert_eq!(info.type_id(), type_info.type_id()); + assert_eq!(info.type_path(), type_info.type_path()); + } + _ => panic!("Expected ThroughTypeInfo::TypeInfo"), + } + } + + #[test] + fn test_typed_through_primitives() { + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::(); + assert_type_info_is_through::<&'static str>(); + } + + #[test] + fn test_typed_wrapper_outer_variant_matches() { + assert!(matches!( + Vec::::through_type_info(), + ThroughTypeInfo::TypedWrapper(TypedWrapperKind::Vec(..)) + )); + + assert!(matches!( + std::collections::HashMap::::through_type_info(), + ThroughTypeInfo::TypedWrapper(TypedWrapperKind::HashMap(..)) + )); + + assert!(matches!( + Result::::through_type_info(), + ThroughTypeInfo::TypedWrapper(TypedWrapperKind::InteropResult(..)) + )); + + assert!(matches!( + <[i32; 3]>::through_type_info(), + ThroughTypeInfo::TypedWrapper(TypedWrapperKind::Array(..)) + )); + + assert!(matches!( + Option::::through_type_info(), + ThroughTypeInfo::TypedWrapper(TypedWrapperKind::Option(..)) + )); + + assert!(matches!( + <(i32, f32)>::through_type_info(), + ThroughTypeInfo::TypedWrapper(TypedWrapperKind::Tuple(..)) + )); + } +} From 03d24e7802b908fb9d46de325e5fe0cc9f91f5d5 Mon Sep 17 00:00:00 2001 From: makspll Date: Mon, 10 Feb 2025 21:11:17 +0000 Subject: [PATCH 3/3] add some more tests --- .../src/docgen/info.rs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/crates/bevy_mod_scripting_core/src/docgen/info.rs b/crates/bevy_mod_scripting_core/src/docgen/info.rs index bfc582cca1..b22b460770 100644 --- a/crates/bevy_mod_scripting_core/src/docgen/info.rs +++ b/crates/bevy_mod_scripting_core/src/docgen/info.rs @@ -187,6 +187,20 @@ mod test { assert_eq!(info.arg_info[0].type_id, TypeId::of::()); assert_eq!(info.arg_info[1].type_id, TypeId::of::()); + + match info.arg_info[0].type_info.as_ref().unwrap() { + ThroughTypeInfo::TypeInfo(type_info) => { + assert_eq!(type_info.type_id(), TypeId::of::()); + } + _ => panic!("Expected TypeInfo"), + } + + match info.arg_info[1].type_info.as_ref().unwrap() { + ThroughTypeInfo::TypeInfo(type_info) => { + assert_eq!(type_info.type_id(), TypeId::of::()); + } + _ => panic!("Expected TypeInfo"), + } } #[test] @@ -201,5 +215,31 @@ mod test { assert_eq!(info.arg_info[0].type_id, TypeId::of::>()); assert_eq!(info.arg_info[1].type_id, TypeId::of::>()); + + match info.arg_info[0].type_info.as_ref().unwrap() { + ThroughTypeInfo::UntypedWrapper { + through_type, + wrapper_type_id, + wrapper_name, + } => { + assert_eq!(through_type.type_id(), TypeId::of::()); + assert_eq!(*wrapper_type_id, TypeId::of::>()); + assert_eq!(*wrapper_name, "Ref"); + } + _ => panic!("Expected UntypedWrapper"), + } + + match info.arg_info[1].type_info.as_ref().unwrap() { + ThroughTypeInfo::UntypedWrapper { + through_type, + wrapper_type_id, + wrapper_name, + } => { + assert_eq!(through_type.type_id(), TypeId::of::()); + assert_eq!(*wrapper_type_id, TypeId::of::>()); + assert_eq!(*wrapper_name, "Mut"); + } + _ => panic!("Expected UntypedWrapper"), + } } }