From 830a432b3b4e6ed2bcf98de22c55dcf6c2446e20 Mon Sep 17 00:00:00 2001 From: makspll Date: Tue, 11 Feb 2025 20:19:45 +0000 Subject: [PATCH 1/8] feat: create `lad` file format --- crates/bevy_mod_scripting_core/Cargo.toml | 7 + .../src/bindings/function/mod.rs | 2 +- .../src/docgen/info.rs | 43 +- .../src/docgen/ladfile.rs | 798 ++++++++++++++++++ .../bevy_mod_scripting_core/src/docgen/mod.rs | 1 + .../src/docgen/test_assets/test.lad.json | 239 ++++++ .../src/docgen/typed_through.rs | 19 +- 7 files changed, 1087 insertions(+), 22 deletions(-) create mode 100644 crates/bevy_mod_scripting_core/src/docgen/ladfile.rs create mode 100644 crates/bevy_mod_scripting_core/src/docgen/test_assets/test.lad.json diff --git a/crates/bevy_mod_scripting_core/Cargo.toml b/crates/bevy_mod_scripting_core/Cargo.toml index f657f88b68..d058c31b6e 100644 --- a/crates/bevy_mod_scripting_core/Cargo.toml +++ b/crates/bevy_mod_scripting_core/Cargo.toml @@ -34,6 +34,9 @@ bevy = { workspace = true, default-features = false, features = [ "bevy_asset", "reflect_functions", ] } +# I don't think bevy has a top level feature for this :C +bevy_reflect = { version = "0.15.1", features = ["documentation"] } + thiserror = "1.0.31" parking_lot = "0.12.1" dashmap = "6" @@ -42,6 +45,10 @@ itertools = "0.13" derivative = "2.2" profiling = { workspace = true } bevy_mod_scripting_derive = { workspace = true } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +indexmap = { version = "2.7", features = ["serde"] } + [dev-dependencies] test_utils = { workspace = true } 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 6c5e08e121..d659932ea2 100644 --- a/crates/bevy_mod_scripting_core/src/bindings/function/mod.rs +++ b/crates/bevy_mod_scripting_core/src/bindings/function/mod.rs @@ -69,7 +69,7 @@ mod test { assert_eq!(test_fn.info.arg_info[1].name, Some("_arg1".into())); assert_eq!( - test_fn.info.return_info.as_ref().unwrap().type_id, + test_fn.info.return_info.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 b22b460770..4fa182b900 100644 --- a/crates/bevy_mod_scripting_core/src/docgen/info.rs +++ b/crates/bevy_mod_scripting_core/src/docgen/info.rs @@ -23,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: Option, + pub return_info: FunctionReturnInfo, /// Documentation for the function. pub docs: Option>, } @@ -41,7 +41,7 @@ impl FunctionInfo { name: Cow::Borrowed(""), namespace: Namespace::Global, arg_info: Vec::new(), - return_info: None, + return_info: FunctionReturnInfo::default(), docs: None, } } @@ -52,7 +52,7 @@ impl FunctionInfo { name, namespace, arg_info: Vec::new(), - return_info: None, + return_info: FunctionReturnInfo::default(), docs: None, } } @@ -69,7 +69,7 @@ impl FunctionInfo { /// Add a return value to the function info. pub fn add_return(mut self) -> Self { - self.return_info = Some(FunctionReturnInfo::new_for::()); + self.return_info = FunctionReturnInfo::new_for::(); self } @@ -136,6 +136,12 @@ pub struct FunctionReturnInfo { pub type_id: TypeId, } +impl Default for FunctionReturnInfo { + fn default() -> Self { + Self::new_for::<()>() + } +} + impl FunctionReturnInfo { /// Create a new function return info for a specific type. pub fn new_for() -> Self { @@ -169,7 +175,10 @@ bevy::utils::all_tuples!(impl_documentable, 0, 13, T); #[cfg(test)] mod test { - use crate::bindings::function::from::{Mut, Ref, Val}; + use crate::{ + bindings::function::from::{Mut, Ref, Val}, + docgen::typed_through::UntypedWrapperKind, + }; use super::*; @@ -183,7 +192,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.unwrap().type_id, TypeId::of::()); + assert_eq!(info.return_info.type_id, TypeId::of::()); assert_eq!(info.arg_info[0].type_id, TypeId::of::()); assert_eq!(info.arg_info[1].type_id, TypeId::of::()); @@ -211,33 +220,33 @@ 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.unwrap().type_id, TypeId::of::>()); + assert_eq!(info.return_info.type_id, TypeId::of::>()); 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 { + match &info.arg_info[0].type_info { + Some(ThroughTypeInfo::UntypedWrapper { through_type, wrapper_type_id, - wrapper_name, - } => { + wrapper_kind, + }) => { assert_eq!(through_type.type_id(), TypeId::of::()); assert_eq!(*wrapper_type_id, TypeId::of::>()); - assert_eq!(*wrapper_name, "Ref"); + assert_eq!(*wrapper_kind, UntypedWrapperKind::Ref); } _ => panic!("Expected UntypedWrapper"), } - match info.arg_info[1].type_info.as_ref().unwrap() { - ThroughTypeInfo::UntypedWrapper { + match &info.arg_info[1].type_info { + Some(ThroughTypeInfo::UntypedWrapper { through_type, wrapper_type_id, - wrapper_name, - } => { + wrapper_kind, + }) => { assert_eq!(through_type.type_id(), TypeId::of::()); assert_eq!(*wrapper_type_id, TypeId::of::>()); - assert_eq!(*wrapper_name, "Mut"); + assert_eq!(*wrapper_kind, UntypedWrapperKind::Mut); } _ => panic!("Expected UntypedWrapper"), } diff --git a/crates/bevy_mod_scripting_core/src/docgen/ladfile.rs b/crates/bevy_mod_scripting_core/src/docgen/ladfile.rs new file mode 100644 index 0000000000..bfc0a7c7c4 --- /dev/null +++ b/crates/bevy_mod_scripting_core/src/docgen/ladfile.rs @@ -0,0 +1,798 @@ +//! Parsing definitions for the LAD (Language Agnostic Decleration) file format. + +use super::{ + info::FunctionInfo, + typed_through::{ThroughTypeInfo, UntypedWrapperKind}, +}; +use crate::{ + bindings::{function::script_function::FunctionCallContext, ReflectReference}, + match_by_type, +}; +use bevy::reflect::TypeInfo; +use bevy_reflect::{ + func::{DynamicFunction, DynamicFunctionMut}, + NamedField, Reflect, TypeRegistry, Typed, UnnamedField, +}; +use indexmap::IndexMap; +use std::{any::TypeId, borrow::Cow, collections::HashMap, ffi::OsString, path::PathBuf}; + +const LAD_VERSION: &str = "0.1.0"; + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +/// A Language Agnostic Declaration (LAD) file. +pub struct LadFile { + /// The version of the LAD file format used. + pub version: Cow<'static, str>, + + /// The types defined in the LAD file. + pub types: IndexMap, + + /// The functions defined in the LAD file. + pub functions: IndexMap, + + /// A mapping from type ids to primitive types + pub primitives: IndexMap, +} + +impl LadFile { + /// Create a new empty LAD file. + pub fn new() -> Self { + Self { + version: LAD_VERSION.into(), + types: IndexMap::new(), + functions: IndexMap::new(), + primitives: IndexMap::new(), + } + } +} + +impl Default for LadFile { + fn default() -> Self { + Self::new() + } +} + +#[derive( + Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, +)] +/// A unique identifier for a function in a LAD file. +/// Only unique within the LAD file. +pub struct LadFunctionId(String); + +impl LadFunctionId { + /// Create a new LAD function id with a string. + pub fn new_string_id(function_id: String) -> Self { + LadFunctionId(function_id) + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +/// A function definition used in a LAD file. +pub struct LadFunction { + /// The identifier or name of the function. + pub identifier: Cow<'static, str>, + /// The argument information for the function. + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub arguments: Vec, + /// The return type of the function. + pub return_type: LadTypeId, + /// The documentation describing the function. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub documentation: Option>, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +/// An argument definition used in a LAD file. +pub struct LadArgument { + /// The kind and type of argument + pub kind: LadArgumentKind, + /// The name of the argument + #[serde(skip_serializing_if = "Option::is_none", default)] + pub name: Option>, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +/// The kind of an argument in a LAD file. +#[serde(rename_all = "camelCase")] +pub enum LadArgumentKind { + /// a `Ref` wrapped argument + Ref(LadTypeId), + /// a `Mut` wrapped argument + Mut(LadTypeId), + /// a `Val` wrapped argument + Val(LadTypeId), + /// an `Option` wrapped argument + Option(Box), + /// a `Vec` + Vec(Box), + /// a `HashMap` + HashMap(Box, Box), + /// A `InteropResult` + InteropResult(Box), + /// A tuple of arguments + Tuple(Vec), + /// An array + Array(Box, usize), + /// A primitive type, implementing `IntoScript` and `FromScript` natively in BMS. + Primitive(LadBMSPrimitiveKind), + /// An arbitrary type which is either unsupported, doesn't contain type information, or is generally unknown. + /// + /// This will be the variant used for external primitives as well. + Unknown(LadTypeId), +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +/// A BMS primitive definition +pub struct LadBMSPrimitiveType { + /// The kind of primitive + pub kind: LadBMSPrimitiveKind, + /// The documentation describing the primitive + pub documentation: Cow<'static, str>, +} + +/// A primitive type kind in the LAD file format. +/// +/// The docstrings on variants corresponding to Reflect types, are used to generate documentation for these primitives. +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Reflect)] +#[serde(rename_all = "camelCase")] +// #[serde(untagged)] +#[allow(missing_docs)] +pub enum LadBMSPrimitiveKind { + Bool, + Isize, + I8, + I16, + I32, + I64, + I128, + Usize, + U8, + U16, + U32, + U64, + U128, + F32, + F64, + Char, + Str, + String, + OsString, + PathBuf, + FunctionCallContext, + DynamicFunction, + DynamicFunctionMut, + ReflectReference, +} + +#[derive( + Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, +)] +/// A unique identifier for a type in a LAD file. +/// +/// Only guaranteed to be unique within the LAD file. +/// It *might* be unique across LAD files, but this is not guaranteed and depends on the type itself. +pub struct LadTypeId(Cow<'static, str>); + +impl LadTypeId { + /// Create a new LAD type id with a specific index. + pub fn new_string_id(type_id: Cow<'static, str>) -> Self { + LadTypeId(type_id) + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +/// A type definition used in a LAD file. +pub struct LadType { + /// The identifier or name of the type. + pub identifier: String, + + /// The source crate of the type + #[serde(rename = "crate", skip_serializing_if = "Option::is_none", default)] + pub crate_: Option, + + /// The full path of the type + pub path: String, + + /// The generic parameters of the type. + /// + /// Generics are always monomorphized in the LAD file format. + /// Meaning that they are always assigned a concrete type. + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub generics: Vec, + + /// The documentation describing the type. + #[serde(skip_serializing_if = "Option::is_none", default)] + pub documentation: Option, + + /// Functions which are "associated" with this type. + /// I.e. those which are either methods or static functions of this type. + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub associated_functions: Vec, + + /// The layout or kind of the type. + pub layout: LadTypeLayout, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +/// Description of a type layout in a LAD file. +pub enum LadTypeLayout { + /// A type with hidden layout + Opaque, + /// A type with at least one variant + MonoVariant(LadVariant), + /// A type with multiple variants + Enum(Vec), +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "kind")] +/// A variant definition used in a LAD file. +pub enum LadVariant { + /// A tuple struct variant i.e. a struct with unnamed fields. + TupleStruct { + /// The name of the variant. + /// + /// For types which are not Enums, this will simply be the name of the type or its path if no identifier is present. + name: Cow<'static, str>, + + /// The fields of the tuple struct variant. + #[serde(skip_serializing_if = "Vec::is_empty", default)] + fields: Vec, + }, + /// A struct variant i.e. a struct with named fields. + Struct { + /// The name of the variant. + /// + /// For types which are not Enums, this will simply be the name of the type or its path if no identifier is present. + name: Cow<'static, str>, + + /// The fields of the struct variant. + #[serde(skip_serializing_if = "Vec::is_empty", default)] + fields: Vec, + }, + /// A unit variant i.e. a type with no fields + Unit { + /// The name of the variant. + /// + /// For types which are not Enums, this will simply be the name of the type or its path if no identifier is present. + name: Cow<'static, str>, + }, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +/// A field definition used in a LAD file. +pub struct LadField { + #[serde(rename = "type")] + type_: LadTypeId, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +/// A named field definition used in a LAD file. +pub struct LadNamedField { + name: String, + #[serde(rename = "type")] + type_: LadTypeId, +} + +/// A generic type definition used in a LAD file. +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct LadGeneric { + /// The id of the type assigned to this generic. + pub type_id: LadTypeId, + /// The name of the generic + pub name: String, +} + +/// A builder for constructing LAD files. +/// This should be your preferred way of constructing LAD files. +pub struct LadFileBuilder<'t> { + file: LadFile, + type_id_mapping: HashMap, + type_registry: &'t TypeRegistry, + sorted: bool, +} + +impl<'t> LadFileBuilder<'t> { + /// Create a new LAD file builder loaded with primitives. + pub fn new(type_registry: &'t TypeRegistry) -> Self { + let mut builder = Self { + file: LadFile::new(), + type_id_mapping: HashMap::new(), + type_registry, + sorted: false, + }; + + builder + .add_bms_primitive::("A boolean value") + .add_bms_primitive::("A signed pointer-sized integer") + .add_bms_primitive::("A signed 8-bit integer") + .add_bms_primitive::("A signed 16-bit integer") + .add_bms_primitive::("A signed 32-bit integer") + .add_bms_primitive::("A signed 64-bit integer") + .add_bms_primitive::("A signed 128-bit integer") + .add_bms_primitive::("An unsigned pointer-sized integer") + .add_bms_primitive::("An unsigned 8-bit integer") + .add_bms_primitive::("An unsigned 16-bit integer") + .add_bms_primitive::("An unsigned 32-bit integer") + .add_bms_primitive::("An unsigned 64-bit integer") + .add_bms_primitive::("An unsigned 128-bit integer") + .add_bms_primitive::("A 32-bit floating point number") + .add_bms_primitive::("A 64-bit floating point number") + .add_bms_primitive::("An 8-bit character") + .add_bms_primitive::<&'static str>("A static string slice") + .add_bms_primitive::("A heap allocated string") + .add_bms_primitive::("A heap allocated OS string") + .add_bms_primitive::("A heap allocated file path") + .add_bms_primitive::("Function call context, if accepted by a function, means the function can access the world in arbitrary ways.") + .add_bms_primitive::("A callable dynamic function") + .add_bms_primitive::("A stateful and callable dynamic function") + .add_bms_primitive::("A reference to a reflectable type"); + + builder + } + + /// Set whether the LAD file should be sorted at build time. + pub fn set_sorted(&mut self, sorted: bool) -> &mut Self { + self.sorted = sorted; + self + } + + /// Add a BMS primitive to the LAD file. + /// Will do nothing if the type is not a BMS primitive. + pub fn add_bms_primitive( + &mut self, + docs: impl Into>, + ) -> &mut Self { + let type_id = self.lad_id_from_type_id(TypeId::of::()); + let kind = match Self::lad_primitive_type_from_type_id(TypeId::of::()) { + Some(primitive) => primitive, + None => return self, + }; + self.file.primitives.insert( + type_id, + LadBMSPrimitiveType { + kind, + documentation: docs.into(), + }, + ); + self + } + + /// Add a type definition to the LAD file. + /// + /// Equivalent to calling [`Self::add_type_info`] with `T::type_info()`. + pub fn add_type(&mut self) -> &mut Self { + self.add_type_info(T::type_info()); + self + } + + /// Add a type definition to the LAD file. + /// Will overwrite any existing type definitions with the same type id. + pub fn add_type_info(&mut self, type_info: &TypeInfo) -> &mut Self { + let type_id = self.lad_id_from_type_id(type_info.type_id()); + let lad_type = LadType { + identifier: type_info + .type_path_table() + .ident() + .unwrap_or_default() + .to_string(), + generics: type_info + .generics() + .iter() + .map(|param| LadGeneric { + type_id: self.lad_id_from_type_id(param.type_id()), + name: param.name().to_string(), + }) + .collect(), + documentation: type_info.docs().map(|s| s.to_string()), + associated_functions: Vec::new(), + crate_: type_info + .type_path_table() + .crate_name() + .map(|s| s.to_owned()), + path: type_info.type_path_table().path().to_owned(), + layout: self.lad_layout_from_type_info(type_info), + }; + self.file.types.insert(type_id, lad_type); + self + } + + /// Add a function definition to the LAD file. + /// Will overwrite any existing function definitions with the same function id. + pub fn add_function_info(&mut self, function_info: FunctionInfo) -> &mut Self { + let function_id = self.lad_function_id_from_info(&function_info); + let lad_function = LadFunction { + identifier: function_info.name, + arguments: function_info + .arg_info + .into_iter() + .map(|arg| { + let kind = match &arg.type_info { + Some(through_type) => { + self.lad_argument_type_from_through_type(through_type) + } + None => LadArgumentKind::Unknown(self.lad_id_from_type_id(arg.type_id)), + }; + LadArgument { + kind, + name: arg.name, + } + }) + .collect(), + return_type: self.lad_id_from_type_id(function_info.return_info.type_id), + documentation: function_info.docs, + }; + self.file.functions.insert(function_id, lad_function); + self + } + + /// Build the finalized and optimized LAD file. + pub fn build(&mut self) -> LadFile { + let mut file = std::mem::replace(&mut self.file, LadFile::new()); + if self.sorted { + file.types.sort_keys(); + file.functions.sort_keys(); + file.primitives.sort_keys(); + } + + file + } + + fn variant_identifier_for_non_enum(type_info: &TypeInfo) -> Cow<'static, str> { + type_info + .type_path_table() + .ident() + .unwrap_or_else(|| type_info.type_path_table().path()) + .into() + } + + fn struct_variant_from_named_fields<'a, I: Iterator>( + &mut self, + name: Cow<'static, str>, + fields: I, + ) -> LadVariant { + LadVariant::Struct { + name, + fields: fields + .map(|field| LadNamedField { + name: field.name().to_string(), + type_: self.lad_id_from_type_id(field.type_id()), + }) + .collect(), + } + } + + fn tuple_struct_variant_from_fields<'a, I: Iterator>( + &mut self, + name: Cow<'static, str>, + fields: I, + ) -> LadVariant { + LadVariant::TupleStruct { + name, + fields: fields + .map(|field| LadField { + type_: self.lad_id_from_type_id(field.type_id()), + }) + .collect(), + } + } + + fn lad_layout_from_type_info(&mut self, type_info: &TypeInfo) -> LadTypeLayout { + match type_info { + TypeInfo::Struct(struct_info) => { + let fields = (0..struct_info.field_len()).filter_map(|i| struct_info.field_at(i)); + + LadTypeLayout::MonoVariant(self.struct_variant_from_named_fields( + Self::variant_identifier_for_non_enum(type_info), + fields, + )) + } + TypeInfo::TupleStruct(tuple_struct_info) => { + let fields = (0..tuple_struct_info.field_len()) + .filter_map(|i| tuple_struct_info.field_at(i)); + + LadTypeLayout::MonoVariant(self.tuple_struct_variant_from_fields( + Self::variant_identifier_for_non_enum(type_info), + fields, + )) + } + TypeInfo::Enum(enum_info) => { + let mut variants = Vec::new(); + for i in 0..enum_info.variant_len() { + if let Some(variant) = enum_info.variant_at(i) { + let variant_name = variant.name(); + let variant = match variant { + bevy_reflect::VariantInfo::Struct(struct_variant_info) => { + let fields = (0..struct_variant_info.field_len()) + .filter_map(|i| struct_variant_info.field_at(i)); + + self.struct_variant_from_named_fields(variant_name.into(), fields) + } + bevy_reflect::VariantInfo::Tuple(tuple_variant_info) => { + let fields = (0..tuple_variant_info.field_len()) + .filter_map(|i| tuple_variant_info.field_at(i)); + + self.tuple_struct_variant_from_fields(variant_name.into(), fields) + } + bevy_reflect::VariantInfo::Unit(_) => LadVariant::Unit { + name: variant_name.into(), + }, + }; + variants.push(variant); + } + } + LadTypeLayout::Enum(variants) + } + _ => LadTypeLayout::Opaque, + } + } + + fn lad_id_from_type_id(&mut self, type_id: TypeId) -> LadTypeId { + if let Some(lad_id) = self.type_id_mapping.get(&type_id) { + return lad_id.clone(); + } + let new_id = match self.type_registry.get_type_info(type_id) { + Some(info) => info.type_path_table().path().to_owned(), + None => format!("{type_id:?}"), + }; + + let lad_id = LadTypeId::new_string_id(new_id.into()); + self.type_id_mapping.insert(type_id, lad_id.clone()); + lad_id + } + + fn lad_function_id_from_info(&mut self, function_info: &FunctionInfo) -> LadFunctionId { + let namespace_string = match function_info.namespace { + crate::bindings::function::namespace::Namespace::Global => "".to_string(), + crate::bindings::function::namespace::Namespace::OnType(type_id) => { + self.lad_id_from_type_id(type_id).0.to_string() + } + }; + + LadFunctionId::new_string_id(format!("{}::{}", namespace_string, function_info.name)) + } + + /// We can assume that the types here will be either primitives + /// or reflect types, as the rest will be covered by typed wrappers + /// so just check + fn lad_primitive_type_from_type_id(type_id: TypeId) -> Option { + match_by_type!(match type_id { + i: bool => return Some(LadBMSPrimitiveKind::Bool), + i: isize => return Some(LadBMSPrimitiveKind::Isize), + i: i8 => return Some(LadBMSPrimitiveKind::I8), + i: i16 => return Some(LadBMSPrimitiveKind::I16), + i: i32 => return Some(LadBMSPrimitiveKind::I32), + i: i64 => return Some(LadBMSPrimitiveKind::I64), + i: i128 => return Some(LadBMSPrimitiveKind::I128), + i: usize => return Some(LadBMSPrimitiveKind::Usize), + i: u8 => return Some(LadBMSPrimitiveKind::U8), + i: u16 => return Some(LadBMSPrimitiveKind::U16), + i: u32 => return Some(LadBMSPrimitiveKind::U32), + i: u64 => return Some(LadBMSPrimitiveKind::U64), + i: u128 => return Some(LadBMSPrimitiveKind::U128), + i: f32 => return Some(LadBMSPrimitiveKind::F32), + i: f64 => return Some(LadBMSPrimitiveKind::F64), + i: char => return Some(LadBMSPrimitiveKind::Char), + i: &'static str => return Some(LadBMSPrimitiveKind::Str), + i: String => return Some(LadBMSPrimitiveKind::String), + i: OsString => return Some(LadBMSPrimitiveKind::OsString), + i: PathBuf => return Some(LadBMSPrimitiveKind::PathBuf), + i: FunctionCallContext => return Some(LadBMSPrimitiveKind::FunctionCallContext), + i: DynamicFunction => return Some(LadBMSPrimitiveKind::DynamicFunction), + i: DynamicFunctionMut => return Some(LadBMSPrimitiveKind::DynamicFunctionMut), + i: ReflectReference => return Some(LadBMSPrimitiveKind::ReflectReference) + }); + + None + } + + fn lad_argument_type_from_through_type( + &mut self, + through_type: &ThroughTypeInfo, + ) -> LadArgumentKind { + match through_type { + ThroughTypeInfo::UntypedWrapper { + through_type, + wrapper_kind, + .. + } => match wrapper_kind { + UntypedWrapperKind::Ref => { + LadArgumentKind::Ref(self.lad_id_from_type_id(through_type.type_id())) + } + UntypedWrapperKind::Mut => { + LadArgumentKind::Mut(self.lad_id_from_type_id(through_type.type_id())) + } + UntypedWrapperKind::Val => { + LadArgumentKind::Val(self.lad_id_from_type_id(through_type.type_id())) + } + }, + ThroughTypeInfo::TypedWrapper(typed_wrapper_kind) => match typed_wrapper_kind { + super::typed_through::TypedWrapperKind::Vec(through_type_info) => { + LadArgumentKind::Vec(Box::new( + self.lad_argument_type_from_through_type(through_type_info), + )) + } + super::typed_through::TypedWrapperKind::HashMap( + through_type_info, + through_type_info1, + ) => LadArgumentKind::HashMap( + Box::new(self.lad_argument_type_from_through_type(through_type_info)), + Box::new(self.lad_argument_type_from_through_type(through_type_info1)), + ), + super::typed_through::TypedWrapperKind::Array(through_type_info, size) => { + LadArgumentKind::Array( + Box::new(self.lad_argument_type_from_through_type(through_type_info)), + *size, + ) + } + super::typed_through::TypedWrapperKind::Option(through_type_info) => { + LadArgumentKind::Option(Box::new( + self.lad_argument_type_from_through_type(through_type_info), + )) + } + super::typed_through::TypedWrapperKind::InteropResult(through_type_info) => { + LadArgumentKind::InteropResult(Box::new( + self.lad_argument_type_from_through_type(through_type_info), + )) + } + super::typed_through::TypedWrapperKind::Tuple(through_type_infos) => { + LadArgumentKind::Tuple( + through_type_infos + .iter() + .map(|through_type_info| { + self.lad_argument_type_from_through_type(through_type_info) + }) + .collect(), + ) + } + }, + ThroughTypeInfo::TypeInfo(type_info) => { + match Self::lad_primitive_type_from_type_id(type_info.type_id()) { + Some(primitive) => LadArgumentKind::Primitive(primitive), + None => LadArgumentKind::Unknown(self.lad_id_from_type_id(type_info.type_id())), + } + } + } + } +} + +/// Parses a toml string into a LAD file. +pub fn parse_lad_file(toml: &str) -> Result { + serde_json::from_str(toml) +} + +/// Serializes a LAD file into a toml file. +pub fn serialize_lad_file(lad_file: &LadFile, pretty: bool) -> Result { + if pretty { + serde_json::to_string_pretty(lad_file) + } else { + serde_json::to_string(lad_file) + } +} + +#[cfg(test)] +mod test { + use bevy_reflect::Typed; + + use crate::{ + bindings::function::{ + from::Ref, + namespace::{GlobalNamespace, IntoNamespace}, + }, + docgen::info::GetFunctionInfo, + }; + + use super::*; + + /// Set to true to put output into test_assets. + const BLESS_TEST_FILE: bool = true; + + #[test] + fn test_empty_lad_file_serializes_correctly() { + let lad_file = LadFile::new(); + let serialized = serialize_lad_file(&lad_file, false).unwrap(); + let deserialized = parse_lad_file(&serialized).unwrap(); + assert_eq!(lad_file, deserialized); + assert_eq!(deserialized.version, LAD_VERSION); + } + + #[test] + fn test_serializes_as_expected() { + let mut type_registry = TypeRegistry::default(); + type_registry.register::(); + type_registry.register::(); + + #[derive(Reflect)] + /// I am a struct + struct StructType { + /// hello from field + field: usize, + /// hello from field 2 + field2: T, + } + + #[derive(Reflect)] + /// I am a unit test type + struct UnitType; + + #[derive(Reflect)] + /// I am a tuple test type + struct TupleStructType(pub usize, #[doc = "hello"] pub String); + + #[derive(Reflect)] + enum EnumType { + /// hello from variant + Unit, + /// hello from variant 2 + Struct { + /// hello from field + field: usize, + }, + /// hello from variant 3 + TupleStruct(usize, #[doc = "asd"] String), + } + + type_registry.register::>(); + type_registry.register::(); + type_registry.register::(); + type_registry.register::(); + + let function = |_: ReflectReference, _: usize| 2usize; + let function_info = function + .get_function_info("hello_world".into(), StructType::::into_namespace()) + .with_docs("hello docs"); + + let function_with_complex_args = + |_: ReflectReference, _: (usize, String), _: Option>>| 2usize; + let function_with_complex_args_info = function_with_complex_args + .get_function_info("hello_world".into(), StructType::::into_namespace()) + .with_arg_names(&["ref_", "tuple", "option_vec_ref_wrapper"]); + + let global_function = |_: usize| 2usize; + let global_function_info = global_function + .get_function_info("hello_world".into(), GlobalNamespace::into_namespace()) + .with_arg_names(&["arg1"]); + + let lad_file = LadFileBuilder::new(&type_registry) + .set_sorted(true) + .add_function_info(function_info) + .add_function_info(global_function_info) + .add_function_info(function_with_complex_args_info) + .add_type::>() + .add_type::() + .add_type::() + .add_type_info(EnumType::type_info()) + .build(); + let serialized = serialize_lad_file(&lad_file, true).unwrap(); + + if BLESS_TEST_FILE { + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + let path_to_test_assets = std::path::Path::new(&manifest_dir) + .join("src") + .join("docgen") + .join("test_assets"); + + println!("Blessing test file at {:?}", path_to_test_assets); + std::fs::write(path_to_test_assets.join("test.lad.json"), &serialized).unwrap(); + return; + } + + let expected = include_str!("test_assets/test.lad.json"); + + assert_eq!( + serialized.trim(), + expected.trim(), + "Expected:---\n {}\n---\nGot: ---\n{}\n---", + expected, + serialized + ); + } + + #[test] + fn test_asset_deserializes_correctly() { + let asset = include_str!("test_assets/test.lad.json"); + let deserialized = parse_lad_file(asset).unwrap(); + assert_eq!(deserialized.version, LAD_VERSION); + } +} diff --git a/crates/bevy_mod_scripting_core/src/docgen/mod.rs b/crates/bevy_mod_scripting_core/src/docgen/mod.rs index e74e969692..30921fad38 100644 --- a/crates/bevy_mod_scripting_core/src/docgen/mod.rs +++ b/crates/bevy_mod_scripting_core/src/docgen/mod.rs @@ -1,3 +1,4 @@ //! Documentation generation for scripting languages. pub mod info; +pub mod ladfile; pub mod typed_through; diff --git a/crates/bevy_mod_scripting_core/src/docgen/test_assets/test.lad.json b/crates/bevy_mod_scripting_core/src/docgen/test_assets/test.lad.json new file mode 100644 index 0000000000..4bc4671b79 --- /dev/null +++ b/crates/bevy_mod_scripting_core/src/docgen/test_assets/test.lad.json @@ -0,0 +1,239 @@ +{ + "version": "0.1.0", + "types": { + "bevy_mod_scripting_core::docgen::ladfile::test::EnumType": { + "identifier": "EnumType", + "crate": "bevy_mod_scripting_core", + "path": "bevy_mod_scripting_core::docgen::ladfile::test::EnumType", + "layout": [ + { + "kind": "Unit", + "name": "Unit" + }, + { + "kind": "Struct", + "name": "Struct", + "fields": [ + { + "name": "field", + "type": "usize" + } + ] + }, + { + "kind": "TupleStruct", + "name": "TupleStruct", + "fields": [ + { + "type": "usize" + }, + { + "type": "alloc::string::String" + } + ] + } + ] + }, + "bevy_mod_scripting_core::docgen::ladfile::test::StructType": { + "identifier": "StructType", + "crate": "bevy_mod_scripting_core", + "path": "bevy_mod_scripting_core::docgen::ladfile::test::StructType", + "generics": [ + { + "type_id": "usize", + "name": "T" + } + ], + "documentation": " I am a struct", + "layout": { + "kind": "Struct", + "name": "StructType", + "fields": [ + { + "name": "field", + "type": "usize" + }, + { + "name": "field2", + "type": "usize" + } + ] + } + }, + "bevy_mod_scripting_core::docgen::ladfile::test::TupleStructType": { + "identifier": "TupleStructType", + "crate": "bevy_mod_scripting_core", + "path": "bevy_mod_scripting_core::docgen::ladfile::test::TupleStructType", + "documentation": " I am a tuple test type", + "layout": { + "kind": "TupleStruct", + "name": "TupleStructType", + "fields": [ + { + "type": "usize" + }, + { + "type": "alloc::string::String" + } + ] + } + }, + "bevy_mod_scripting_core::docgen::ladfile::test::UnitType": { + "identifier": "UnitType", + "crate": "bevy_mod_scripting_core", + "path": "bevy_mod_scripting_core::docgen::ladfile::test::UnitType", + "documentation": " I am a unit test type", + "layout": { + "kind": "Struct", + "name": "UnitType" + } + } + }, + "functions": { + "::hello_world": { + "identifier": "hello_world", + "arguments": [ + { + "kind": { + "primitive": "usize" + }, + "name": "arg1" + } + ], + "return_type": "usize" + }, + "bevy_mod_scripting_core::docgen::ladfile::test::StructType::hello_world": { + "identifier": "hello_world", + "arguments": [ + { + "kind": { + "primitive": "reflectReference" + }, + "name": "ref_" + }, + { + "kind": { + "tuple": [ + { + "primitive": "usize" + }, + { + "primitive": "string" + } + ] + }, + "name": "tuple" + }, + { + "kind": { + "option": { + "vec": { + "ref": "bevy_mod_scripting_core::docgen::ladfile::test::EnumType" + } + } + }, + "name": "option_vec_ref_wrapper" + } + ], + "return_type": "usize" + } + }, + "primitives": { + "TypeId(0x0b36ea25c1cf517efce182c726ea2190)": { + "kind": "pathBuf", + "documentation": "A heap allocated file path" + }, + "TypeId(0x1c306727557831f62320b5841ddc7eb3)": { + "kind": "dynamicFunction", + "documentation": "A callable dynamic function" + }, + "TypeId(0x7adbf8cf2ed263727e95f06e821c8654)": { + "kind": "osString", + "documentation": "A heap allocated OS string" + }, + "TypeId(0x7f945ad2d333d63863e3b6f35dfc0c5d)": { + "kind": "dynamicFunctionMut", + "documentation": "A stateful and callable dynamic function" + }, + "TypeId(0xb98b1b7157a6417863eb502cd6cb5d6d)": { + "kind": "str", + "documentation": "A static string slice" + }, + "alloc::string::String": { + "kind": "string", + "documentation": "A heap allocated string" + }, + "bevy_mod_scripting_core::bindings::function::script_function::FunctionCallContext": { + "kind": "functionCallContext", + "documentation": "Function call context, if accepted by a function, means the function can access the world in arbitrary ways." + }, + "bevy_mod_scripting_core::bindings::reference::ReflectReference": { + "kind": "reflectReference", + "documentation": "A reference to a reflectable type" + }, + "bool": { + "kind": "bool", + "documentation": "A boolean value" + }, + "char": { + "kind": "char", + "documentation": "An 8-bit character" + }, + "f32": { + "kind": "f32", + "documentation": "A 32-bit floating point number" + }, + "f64": { + "kind": "f64", + "documentation": "A 64-bit floating point number" + }, + "i128": { + "kind": "i128", + "documentation": "A signed 128-bit integer" + }, + "i16": { + "kind": "i16", + "documentation": "A signed 16-bit integer" + }, + "i32": { + "kind": "i32", + "documentation": "A signed 32-bit integer" + }, + "i64": { + "kind": "i64", + "documentation": "A signed 64-bit integer" + }, + "i8": { + "kind": "i8", + "documentation": "A signed 8-bit integer" + }, + "isize": { + "kind": "isize", + "documentation": "A signed pointer-sized integer" + }, + "u128": { + "kind": "u128", + "documentation": "An unsigned 128-bit integer" + }, + "u16": { + "kind": "u16", + "documentation": "An unsigned 16-bit integer" + }, + "u32": { + "kind": "u32", + "documentation": "An unsigned 32-bit integer" + }, + "u64": { + "kind": "u64", + "documentation": "An unsigned 64-bit integer" + }, + "u8": { + "kind": "u8", + "documentation": "An unsigned 8-bit integer" + }, + "usize": { + "kind": "usize", + "documentation": "An unsigned pointer-sized integer" + } + } +} \ No newline at end of file diff --git a/crates/bevy_mod_scripting_core/src/docgen/typed_through.rs b/crates/bevy_mod_scripting_core/src/docgen/typed_through.rs index 3efb4f1155..e6fefdd88f 100644 --- a/crates/bevy_mod_scripting_core/src/docgen/typed_through.rs +++ b/crates/bevy_mod_scripting_core/src/docgen/typed_through.rs @@ -37,7 +37,7 @@ pub enum ThroughTypeInfo { /// The type id of the wrapper type. wrapper_type_id: TypeId, /// The name of the wrapper type. - wrapper_name: &'static str, + wrapper_kind: UntypedWrapperKind, }, /// A wrapper around a through typed type, which itself is also a `Typed` type. TypedWrapper(TypedWrapperKind), @@ -45,6 +45,17 @@ pub enum ThroughTypeInfo { TypeInfo(&'static TypeInfo), } +#[derive(Debug, Clone, PartialEq, Eq)] +/// The kind of untyped wrapper. +pub enum UntypedWrapperKind { + /// A reference wrapper. + Ref, + /// A mutable reference wrapper. + Mut, + /// A value wrapper. + Val, +} + /// The kind of typed wrapper. #[derive(Debug, Clone)] pub enum TypedWrapperKind { @@ -73,7 +84,7 @@ impl TypedThrough for Ref<'_, T> { ThroughTypeInfo::UntypedWrapper { through_type: T::type_info(), wrapper_type_id: TypeId::of::>(), - wrapper_name: "Ref", + wrapper_kind: UntypedWrapperKind::Ref, } } } @@ -83,7 +94,7 @@ impl TypedThrough for Mut<'_, T> { ThroughTypeInfo::UntypedWrapper { through_type: T::type_info(), wrapper_type_id: TypeId::of::>(), - wrapper_name: "Mut", + wrapper_kind: UntypedWrapperKind::Mut, } } } @@ -93,7 +104,7 @@ impl TypedThrough for Val { ThroughTypeInfo::UntypedWrapper { through_type: T::type_info(), wrapper_type_id: TypeId::of::>(), - wrapper_name: "Val", + wrapper_kind: UntypedWrapperKind::Val, } } } From 63246437197cb11a4c08c20dde34631ac2e365dc Mon Sep 17 00:00:00 2001 From: makspll Date: Tue, 11 Feb 2025 22:04:22 +0000 Subject: [PATCH 2/8] remove comment --- crates/bevy_mod_scripting_core/src/docgen/ladfile.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/bevy_mod_scripting_core/src/docgen/ladfile.rs b/crates/bevy_mod_scripting_core/src/docgen/ladfile.rs index bfc0a7c7c4..31a4183e43 100644 --- a/crates/bevy_mod_scripting_core/src/docgen/ladfile.rs +++ b/crates/bevy_mod_scripting_core/src/docgen/ladfile.rs @@ -135,7 +135,6 @@ pub struct LadBMSPrimitiveType { /// The docstrings on variants corresponding to Reflect types, are used to generate documentation for these primitives. #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Reflect)] #[serde(rename_all = "camelCase")] -// #[serde(untagged)] #[allow(missing_docs)] pub enum LadBMSPrimitiveKind { Bool, From 9bcda076c472761200a485a69fe7b5bf1ea214ff Mon Sep 17 00:00:00 2001 From: makspll Date: Tue, 11 Feb 2025 22:22:47 +0000 Subject: [PATCH 3/8] move ladfile into it's own crate --- Cargo.toml | 2 +- crates/bevy_mod_scripting_core/Cargo.toml | 5 -- .../bevy_mod_scripting_core/src/docgen/mod.rs | 1 - crates/ladfile/.gitignore | 1 + crates/ladfile/Cargo.toml | 15 ++++ .../docgen/ladfile.rs => ladfile/src/lib.rs} | 86 ++++++++----------- .../test_assets/test.lad.json | 0 7 files changed, 54 insertions(+), 56 deletions(-) create mode 100644 crates/ladfile/.gitignore create mode 100644 crates/ladfile/Cargo.toml rename crates/{bevy_mod_scripting_core/src/docgen/ladfile.rs => ladfile/src/lib.rs} (92%) rename crates/{bevy_mod_scripting_core/src/docgen => ladfile}/test_assets/test.lad.json (100%) diff --git a/Cargo.toml b/Cargo.toml index 89ef8c1950..54557c47da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,7 +88,7 @@ members = [ "crates/bevy_mod_scripting_functions", "crates/xtask", "crates/script_integration_test_harness", - "crates/bevy_mod_scripting_derive", + "crates/bevy_mod_scripting_derive", "crates/ladfile", ] resolver = "2" exclude = ["crates/bevy_api_gen", "crates/macro_tests"] diff --git a/crates/bevy_mod_scripting_core/Cargo.toml b/crates/bevy_mod_scripting_core/Cargo.toml index d058c31b6e..d1b5c250f1 100644 --- a/crates/bevy_mod_scripting_core/Cargo.toml +++ b/crates/bevy_mod_scripting_core/Cargo.toml @@ -34,8 +34,6 @@ bevy = { workspace = true, default-features = false, features = [ "bevy_asset", "reflect_functions", ] } -# I don't think bevy has a top level feature for this :C -bevy_reflect = { version = "0.15.1", features = ["documentation"] } thiserror = "1.0.31" parking_lot = "0.12.1" @@ -45,9 +43,6 @@ itertools = "0.13" derivative = "2.2" profiling = { workspace = true } bevy_mod_scripting_derive = { workspace = true } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -indexmap = { version = "2.7", features = ["serde"] } [dev-dependencies] diff --git a/crates/bevy_mod_scripting_core/src/docgen/mod.rs b/crates/bevy_mod_scripting_core/src/docgen/mod.rs index 30921fad38..e74e969692 100644 --- a/crates/bevy_mod_scripting_core/src/docgen/mod.rs +++ b/crates/bevy_mod_scripting_core/src/docgen/mod.rs @@ -1,4 +1,3 @@ //! Documentation generation for scripting languages. pub mod info; -pub mod ladfile; pub mod typed_through; diff --git a/crates/ladfile/.gitignore b/crates/ladfile/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/crates/ladfile/.gitignore @@ -0,0 +1 @@ +/target diff --git a/crates/ladfile/Cargo.toml b/crates/ladfile/Cargo.toml new file mode 100644 index 0000000000..32ebcdc4a7 --- /dev/null +++ b/crates/ladfile/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "ladfile" +version = "0.1.0" +edition = "2021" + +[dependencies] +bevy_mod_scripting_core = { workspace = true } +# I don't think bevy has a top level feature for this :C +bevy_reflect = { version = "0.15.1", features = ["documentation"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +indexmap = { version = "2.7", features = ["serde"] } + +[lints] +workspace = true diff --git a/crates/bevy_mod_scripting_core/src/docgen/ladfile.rs b/crates/ladfile/src/lib.rs similarity index 92% rename from crates/bevy_mod_scripting_core/src/docgen/ladfile.rs rename to crates/ladfile/src/lib.rs index 31a4183e43..f16c6cc1ee 100644 --- a/crates/bevy_mod_scripting_core/src/docgen/ladfile.rs +++ b/crates/ladfile/src/lib.rs @@ -1,17 +1,16 @@ //! Parsing definitions for the LAD (Language Agnostic Decleration) file format. -use super::{ - info::FunctionInfo, - typed_through::{ThroughTypeInfo, UntypedWrapperKind}, -}; -use crate::{ +use bevy_mod_scripting_core::{ bindings::{function::script_function::FunctionCallContext, ReflectReference}, + docgen::{ + info::FunctionInfo, + typed_through::{ThroughTypeInfo, TypedWrapperKind, UntypedWrapperKind}, + }, match_by_type, }; -use bevy::reflect::TypeInfo; use bevy_reflect::{ func::{DynamicFunction, DynamicFunctionMut}, - NamedField, Reflect, TypeRegistry, Typed, UnnamedField, + NamedField, Reflect, TypeInfo, TypeRegistry, Typed, UnnamedField, }; use indexmap::IndexMap; use std::{any::TypeId, borrow::Cow, collections::HashMap, ffi::OsString, path::PathBuf}; @@ -543,8 +542,10 @@ impl<'t> LadFileBuilder<'t> { fn lad_function_id_from_info(&mut self, function_info: &FunctionInfo) -> LadFunctionId { let namespace_string = match function_info.namespace { - crate::bindings::function::namespace::Namespace::Global => "".to_string(), - crate::bindings::function::namespace::Namespace::OnType(type_id) => { + bevy_mod_scripting_core::bindings::function::namespace::Namespace::Global => { + "".to_string() + } + bevy_mod_scripting_core::bindings::function::namespace::Namespace::OnType(type_id) => { self.lad_id_from_type_id(type_id).0.to_string() } }; @@ -607,44 +608,35 @@ impl<'t> LadFileBuilder<'t> { } }, ThroughTypeInfo::TypedWrapper(typed_wrapper_kind) => match typed_wrapper_kind { - super::typed_through::TypedWrapperKind::Vec(through_type_info) => { - LadArgumentKind::Vec(Box::new( - self.lad_argument_type_from_through_type(through_type_info), - )) - } - super::typed_through::TypedWrapperKind::HashMap( - through_type_info, - through_type_info1, - ) => LadArgumentKind::HashMap( - Box::new(self.lad_argument_type_from_through_type(through_type_info)), - Box::new(self.lad_argument_type_from_through_type(through_type_info1)), - ), - super::typed_through::TypedWrapperKind::Array(through_type_info, size) => { - LadArgumentKind::Array( + TypedWrapperKind::Vec(through_type_info) => LadArgumentKind::Vec(Box::new( + self.lad_argument_type_from_through_type(through_type_info), + )), + TypedWrapperKind::HashMap(through_type_info, through_type_info1) => { + LadArgumentKind::HashMap( Box::new(self.lad_argument_type_from_through_type(through_type_info)), - *size, + Box::new(self.lad_argument_type_from_through_type(through_type_info1)), ) } - super::typed_through::TypedWrapperKind::Option(through_type_info) => { - LadArgumentKind::Option(Box::new( - self.lad_argument_type_from_through_type(through_type_info), - )) - } - super::typed_through::TypedWrapperKind::InteropResult(through_type_info) => { + TypedWrapperKind::Array(through_type_info, size) => LadArgumentKind::Array( + Box::new(self.lad_argument_type_from_through_type(through_type_info)), + *size, + ), + TypedWrapperKind::Option(through_type_info) => LadArgumentKind::Option(Box::new( + self.lad_argument_type_from_through_type(through_type_info), + )), + TypedWrapperKind::InteropResult(through_type_info) => { LadArgumentKind::InteropResult(Box::new( self.lad_argument_type_from_through_type(through_type_info), )) } - super::typed_through::TypedWrapperKind::Tuple(through_type_infos) => { - LadArgumentKind::Tuple( - through_type_infos - .iter() - .map(|through_type_info| { - self.lad_argument_type_from_through_type(through_type_info) - }) - .collect(), - ) - } + TypedWrapperKind::Tuple(through_type_infos) => LadArgumentKind::Tuple( + through_type_infos + .iter() + .map(|through_type_info| { + self.lad_argument_type_from_through_type(through_type_info) + }) + .collect(), + ), }, ThroughTypeInfo::TypeInfo(type_info) => { match Self::lad_primitive_type_from_type_id(type_info.type_id()) { @@ -672,15 +664,14 @@ pub fn serialize_lad_file(lad_file: &LadFile, pretty: bool) -> Result Date: Tue, 11 Feb 2025 22:23:38 +0000 Subject: [PATCH 4/8] fix test --- crates/ladfile/test_assets/test.lad.json | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/crates/ladfile/test_assets/test.lad.json b/crates/ladfile/test_assets/test.lad.json index 4bc4671b79..caa95c43d8 100644 --- a/crates/ladfile/test_assets/test.lad.json +++ b/crates/ladfile/test_assets/test.lad.json @@ -1,10 +1,10 @@ { "version": "0.1.0", "types": { - "bevy_mod_scripting_core::docgen::ladfile::test::EnumType": { + "ladfile::test::EnumType": { "identifier": "EnumType", - "crate": "bevy_mod_scripting_core", - "path": "bevy_mod_scripting_core::docgen::ladfile::test::EnumType", + "crate": "ladfile", + "path": "ladfile::test::EnumType", "layout": [ { "kind": "Unit", @@ -34,10 +34,10 @@ } ] }, - "bevy_mod_scripting_core::docgen::ladfile::test::StructType": { + "ladfile::test::StructType": { "identifier": "StructType", - "crate": "bevy_mod_scripting_core", - "path": "bevy_mod_scripting_core::docgen::ladfile::test::StructType", + "crate": "ladfile", + "path": "ladfile::test::StructType", "generics": [ { "type_id": "usize", @@ -60,10 +60,10 @@ ] } }, - "bevy_mod_scripting_core::docgen::ladfile::test::TupleStructType": { + "ladfile::test::TupleStructType": { "identifier": "TupleStructType", - "crate": "bevy_mod_scripting_core", - "path": "bevy_mod_scripting_core::docgen::ladfile::test::TupleStructType", + "crate": "ladfile", + "path": "ladfile::test::TupleStructType", "documentation": " I am a tuple test type", "layout": { "kind": "TupleStruct", @@ -78,10 +78,10 @@ ] } }, - "bevy_mod_scripting_core::docgen::ladfile::test::UnitType": { + "ladfile::test::UnitType": { "identifier": "UnitType", - "crate": "bevy_mod_scripting_core", - "path": "bevy_mod_scripting_core::docgen::ladfile::test::UnitType", + "crate": "ladfile", + "path": "ladfile::test::UnitType", "documentation": " I am a unit test type", "layout": { "kind": "Struct", @@ -102,7 +102,7 @@ ], "return_type": "usize" }, - "bevy_mod_scripting_core::docgen::ladfile::test::StructType::hello_world": { + "ladfile::test::StructType::hello_world": { "identifier": "hello_world", "arguments": [ { @@ -128,7 +128,7 @@ "kind": { "option": { "vec": { - "ref": "bevy_mod_scripting_core::docgen::ladfile::test::EnumType" + "ref": "ladfile::test::EnumType" } } }, From b895219ebed818aeb5c7ff3c5e092d591a8c238f Mon Sep 17 00:00:00 2001 From: makspll Date: Tue, 11 Feb 2025 22:23:50 +0000 Subject: [PATCH 5/8] disable bless --- crates/ladfile/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ladfile/src/lib.rs b/crates/ladfile/src/lib.rs index f16c6cc1ee..2f58a42928 100644 --- a/crates/ladfile/src/lib.rs +++ b/crates/ladfile/src/lib.rs @@ -676,7 +676,7 @@ mod test { use super::*; /// Set to true to put output into test_assets. - const BLESS_TEST_FILE: bool = true; + const BLESS_TEST_FILE: bool = false; #[test] fn test_empty_lad_file_serializes_correctly() { From a68cf4979193b329526c2d679cd738dc3b76d8e2 Mon Sep 17 00:00:00 2001 From: makspll Date: Tue, 11 Feb 2025 22:33:14 +0000 Subject: [PATCH 6/8] configure crates.io and release-plz --- crates/ladfile/Cargo.toml | 8 ++ crates/ladfile/readme.md | 253 ++++++++++++++++++++++++++++++++++++++ release-plz.toml | 27 ++-- 3 files changed, 279 insertions(+), 9 deletions(-) create mode 100644 crates/ladfile/readme.md diff --git a/crates/ladfile/Cargo.toml b/crates/ladfile/Cargo.toml index 32ebcdc4a7..ff909b559b 100644 --- a/crates/ladfile/Cargo.toml +++ b/crates/ladfile/Cargo.toml @@ -2,6 +2,14 @@ name = "ladfile" version = "0.1.0" edition = "2021" +authors = ["Maksymilian Mozolewski "] +license = "MIT OR Apache-2.0" +description = "Language Agnostic Declaration (LAD) file format for the bevy_mod_scripting crate" +repository = "https://github.com/makspll/bevy_mod_scripting" +homepage = "https://github.com/makspll/bevy_mod_scripting" +keywords = ["bevy", "gamedev", "scripting", "format", "json"] +categories = ["game-development", "parser-implementations"] +readme = "readme.md" [dependencies] bevy_mod_scripting_core = { workspace = true } diff --git a/crates/ladfile/readme.md b/crates/ladfile/readme.md new file mode 100644 index 0000000000..ed86ada64b --- /dev/null +++ b/crates/ladfile/readme.md @@ -0,0 +1,253 @@ +# Language Agnostic Declaration file + +A file format specifying the available exported: +- functions +- types +- primitives +- documentation + +For a `bevy` game engine project. + +## Example + +```json +{ + "version": "0.1.0", + "types": { + "ladfile::test::EnumType": { + "identifier": "EnumType", + "crate": "ladfile", + "path": "ladfile::test::EnumType", + "layout": [ + { + "kind": "Unit", + "name": "Unit" + }, + { + "kind": "Struct", + "name": "Struct", + "fields": [ + { + "name": "field", + "type": "usize" + } + ] + }, + { + "kind": "TupleStruct", + "name": "TupleStruct", + "fields": [ + { + "type": "usize" + }, + { + "type": "alloc::string::String" + } + ] + } + ] + }, + "ladfile::test::StructType": { + "identifier": "StructType", + "crate": "ladfile", + "path": "ladfile::test::StructType", + "generics": [ + { + "type_id": "usize", + "name": "T" + } + ], + "documentation": " I am a struct", + "layout": { + "kind": "Struct", + "name": "StructType", + "fields": [ + { + "name": "field", + "type": "usize" + }, + { + "name": "field2", + "type": "usize" + } + ] + } + }, + "ladfile::test::TupleStructType": { + "identifier": "TupleStructType", + "crate": "ladfile", + "path": "ladfile::test::TupleStructType", + "documentation": " I am a tuple test type", + "layout": { + "kind": "TupleStruct", + "name": "TupleStructType", + "fields": [ + { + "type": "usize" + }, + { + "type": "alloc::string::String" + } + ] + } + }, + "ladfile::test::UnitType": { + "identifier": "UnitType", + "crate": "ladfile", + "path": "ladfile::test::UnitType", + "documentation": " I am a unit test type", + "layout": { + "kind": "Struct", + "name": "UnitType" + } + } + }, + "functions": { + "::hello_world": { + "identifier": "hello_world", + "arguments": [ + { + "kind": { + "primitive": "usize" + }, + "name": "arg1" + } + ], + "return_type": "usize" + }, + "ladfile::test::StructType::hello_world": { + "identifier": "hello_world", + "arguments": [ + { + "kind": { + "primitive": "reflectReference" + }, + "name": "ref_" + }, + { + "kind": { + "tuple": [ + { + "primitive": "usize" + }, + { + "primitive": "string" + } + ] + }, + "name": "tuple" + }, + { + "kind": { + "option": { + "vec": { + "ref": "ladfile::test::EnumType" + } + } + }, + "name": "option_vec_ref_wrapper" + } + ], + "return_type": "usize" + } + }, + "primitives": { + "TypeId(0x0b36ea25c1cf517efce182c726ea2190)": { + "kind": "pathBuf", + "documentation": "A heap allocated file path" + }, + "TypeId(0x1c306727557831f62320b5841ddc7eb3)": { + "kind": "dynamicFunction", + "documentation": "A callable dynamic function" + }, + "TypeId(0x7adbf8cf2ed263727e95f06e821c8654)": { + "kind": "osString", + "documentation": "A heap allocated OS string" + }, + "TypeId(0x7f945ad2d333d63863e3b6f35dfc0c5d)": { + "kind": "dynamicFunctionMut", + "documentation": "A stateful and callable dynamic function" + }, + "TypeId(0xb98b1b7157a6417863eb502cd6cb5d6d)": { + "kind": "str", + "documentation": "A static string slice" + }, + "alloc::string::String": { + "kind": "string", + "documentation": "A heap allocated string" + }, + "bevy_mod_scripting_core::bindings::function::script_function::FunctionCallContext": { + "kind": "functionCallContext", + "documentation": "Function call context, if accepted by a function, means the function can access the world in arbitrary ways." + }, + "bevy_mod_scripting_core::bindings::reference::ReflectReference": { + "kind": "reflectReference", + "documentation": "A reference to a reflectable type" + }, + "bool": { + "kind": "bool", + "documentation": "A boolean value" + }, + "char": { + "kind": "char", + "documentation": "An 8-bit character" + }, + "f32": { + "kind": "f32", + "documentation": "A 32-bit floating point number" + }, + "f64": { + "kind": "f64", + "documentation": "A 64-bit floating point number" + }, + "i128": { + "kind": "i128", + "documentation": "A signed 128-bit integer" + }, + "i16": { + "kind": "i16", + "documentation": "A signed 16-bit integer" + }, + "i32": { + "kind": "i32", + "documentation": "A signed 32-bit integer" + }, + "i64": { + "kind": "i64", + "documentation": "A signed 64-bit integer" + }, + "i8": { + "kind": "i8", + "documentation": "A signed 8-bit integer" + }, + "isize": { + "kind": "isize", + "documentation": "A signed pointer-sized integer" + }, + "u128": { + "kind": "u128", + "documentation": "An unsigned 128-bit integer" + }, + "u16": { + "kind": "u16", + "documentation": "An unsigned 16-bit integer" + }, + "u32": { + "kind": "u32", + "documentation": "An unsigned 32-bit integer" + }, + "u64": { + "kind": "u64", + "documentation": "An unsigned 64-bit integer" + }, + "u8": { + "kind": "u8", + "documentation": "An unsigned 8-bit integer" + }, + "usize": { + "kind": "usize", + "documentation": "An unsigned pointer-sized integer" + } + } +} +``` diff --git a/release-plz.toml b/release-plz.toml index 116b184194..bc0497d441 100644 --- a/release-plz.toml +++ b/release-plz.toml @@ -3,6 +3,15 @@ dependencies_update = false publish_timeout = "30m" git_release_enable = false git_tag_enable = false +git_release_body = """ +{{ changelog }} +{% if remote.contributors %} +### Contributors +{% for contributor in remote.contributors %} +* @{{ contributor.username }} +{% endfor %} +{% endif %} +""" [changelog] commit_parsers = [ @@ -27,15 +36,7 @@ git_release_enable = true git_tag_enable = true git_tag_name = "v{{ version }}" git_release_name = "v{{ version }}" -git_release_body = """ -{{ changelog }} -{% if remote.contributors %} -### Contributors -{% for contributor in remote.contributors %} -* @{{ contributor.username }} -{% endfor %} -{% endif %} -""" + changelog_include = [ "bevy_mod_scripting_lua", "bevy_mod_scripting_core", @@ -68,3 +69,11 @@ version_group = "main" [[package]] name = "bevy_mod_scripting_functions" version_group = "main" + +[[package]] +name = "ladfile" +git_release_enable = true +git_release_latest = false +git_tag_enable = true +git_tag_name = "v{{ version }}-ladfile" +git_release_name = "v{{ version }}-ladfile" From a18abaad5c1a8f6cb725d68507e2be506874637a Mon Sep 17 00:00:00 2001 From: makspll Date: Tue, 11 Feb 2025 23:25:21 +0000 Subject: [PATCH 7/8] fill in missing type id's --- .../src/bindings/function/into_ref.rs | 5 - crates/ladfile/src/lib.rs | 135 ++++++++++++------ crates/ladfile/test_assets/test.lad.json | 44 +++--- tealr_doc_gen_config.json | 16 --- tlconfig.lua | 5 - 5 files changed, 112 insertions(+), 93 deletions(-) delete mode 100644 tealr_doc_gen_config.json delete mode 100644 tlconfig.lua diff --git a/crates/bevy_mod_scripting_core/src/bindings/function/into_ref.rs b/crates/bevy_mod_scripting_core/src/bindings/function/into_ref.rs index cda4eb4640..e39b98c246 100644 --- a/crates/bevy_mod_scripting_core/src/bindings/function/into_ref.rs +++ b/crates/bevy_mod_scripting_core/src/bindings/function/into_ref.rs @@ -30,11 +30,6 @@ pub trait IntoScriptRef { /// a utility for matching types by their [`std::any::TypeId`] macro_rules! match_by_type { (match $on:ident {$($id:ident : $ty:ty => $conv:expr),*}) => { - $( - #[allow(unused_variables)] - let $id = std::any::TypeId::of::<$ty>(); - )* - match $on { $( $id if $id == std::any::TypeId::of::<$ty>() => {$conv}, diff --git a/crates/ladfile/src/lib.rs b/crates/ladfile/src/lib.rs index 2f58a42928..459bbcdf26 100644 --- a/crates/ladfile/src/lib.rs +++ b/crates/ladfile/src/lib.rs @@ -162,6 +162,81 @@ pub enum LadBMSPrimitiveKind { ReflectReference, } +impl LadBMSPrimitiveKind { + /// Get the corresponding type id for a primitive kind. + pub fn lad_type_id(self) -> LadTypeId { + match self { + LadBMSPrimitiveKind::Bool => LadTypeId::new_string_id("bool".into()), + LadBMSPrimitiveKind::Isize => LadTypeId::new_string_id("isize".into()), + LadBMSPrimitiveKind::I8 => LadTypeId::new_string_id("i8".into()), + LadBMSPrimitiveKind::I16 => LadTypeId::new_string_id("i16".into()), + LadBMSPrimitiveKind::I32 => LadTypeId::new_string_id("i32".into()), + LadBMSPrimitiveKind::I64 => LadTypeId::new_string_id("i64".into()), + LadBMSPrimitiveKind::I128 => LadTypeId::new_string_id("i128".into()), + LadBMSPrimitiveKind::Usize => LadTypeId::new_string_id("usize".into()), + LadBMSPrimitiveKind::U8 => LadTypeId::new_string_id("u8".into()), + LadBMSPrimitiveKind::U16 => LadTypeId::new_string_id("u16".into()), + LadBMSPrimitiveKind::U32 => LadTypeId::new_string_id("u32".into()), + LadBMSPrimitiveKind::U64 => LadTypeId::new_string_id("u64".into()), + LadBMSPrimitiveKind::U128 => LadTypeId::new_string_id("u128".into()), + LadBMSPrimitiveKind::F32 => LadTypeId::new_string_id("f32".into()), + LadBMSPrimitiveKind::F64 => LadTypeId::new_string_id("f64".into()), + LadBMSPrimitiveKind::Char => LadTypeId::new_string_id("char".into()), + LadBMSPrimitiveKind::Str => LadTypeId::new_string_id("str".into()), + LadBMSPrimitiveKind::String => LadTypeId::new_string_id("String".into()), + LadBMSPrimitiveKind::OsString => LadTypeId::new_string_id("OsString".into()), + LadBMSPrimitiveKind::PathBuf => LadTypeId::new_string_id("PathBuf".into()), + LadBMSPrimitiveKind::FunctionCallContext => { + LadTypeId::new_string_id("FunctionCallContext".into()) + } + LadBMSPrimitiveKind::DynamicFunction => { + LadTypeId::new_string_id("DynamicFunction".into()) + } + LadBMSPrimitiveKind::DynamicFunctionMut => { + LadTypeId::new_string_id("DynamicFunctionMut".into()) + } + LadBMSPrimitiveKind::ReflectReference => { + LadTypeId::new_string_id("ReflectReference".into()) + } + } + } + + /// We can assume that the types here will be either primitives + /// or reflect types, as the rest will be covered by typed wrappers + /// so just check + fn from_type_id(type_id: TypeId) -> Option { + match_by_type!(match type_id { + i: bool => return Some(LadBMSPrimitiveKind::Bool), + i: isize => return Some(LadBMSPrimitiveKind::Isize), + i: i8 => return Some(LadBMSPrimitiveKind::I8), + i: i16 => return Some(LadBMSPrimitiveKind::I16), + i: i32 => return Some(LadBMSPrimitiveKind::I32), + i: i64 => return Some(LadBMSPrimitiveKind::I64), + i: i128 => return Some(LadBMSPrimitiveKind::I128), + i: usize => return Some(LadBMSPrimitiveKind::Usize), + i: u8 => return Some(LadBMSPrimitiveKind::U8), + i: u16 => return Some(LadBMSPrimitiveKind::U16), + i: u32 => return Some(LadBMSPrimitiveKind::U32), + i: u64 => return Some(LadBMSPrimitiveKind::U64), + i: u128 => return Some(LadBMSPrimitiveKind::U128), + i: f32 => return Some(LadBMSPrimitiveKind::F32), + i: f64 => return Some(LadBMSPrimitiveKind::F64), + i: char => return Some(LadBMSPrimitiveKind::Char), + i: &'static str => return Some(LadBMSPrimitiveKind::Str), + i: str => return Some(LadBMSPrimitiveKind::Str), + i: String => return Some(LadBMSPrimitiveKind::String), + i: OsString => return Some(LadBMSPrimitiveKind::OsString), + i: PathBuf => return Some(LadBMSPrimitiveKind::PathBuf), + i: FunctionCallContext => return Some(LadBMSPrimitiveKind::FunctionCallContext), + i: DynamicFunction => return Some(LadBMSPrimitiveKind::DynamicFunction), + i: DynamicFunctionMut => return Some(LadBMSPrimitiveKind::DynamicFunctionMut), + i: ReflectReference => return Some(LadBMSPrimitiveKind::ReflectReference) + }); + + None + } +} + #[derive( Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, )] @@ -318,7 +393,7 @@ impl<'t> LadFileBuilder<'t> { .add_bms_primitive::("A 32-bit floating point number") .add_bms_primitive::("A 64-bit floating point number") .add_bms_primitive::("An 8-bit character") - .add_bms_primitive::<&'static str>("A static string slice") + .add_bms_primitive::<&'static str>("A string slice") .add_bms_primitive::("A heap allocated string") .add_bms_primitive::("A heap allocated OS string") .add_bms_primitive::("A heap allocated file path") @@ -343,7 +418,7 @@ impl<'t> LadFileBuilder<'t> { docs: impl Into>, ) -> &mut Self { let type_id = self.lad_id_from_type_id(TypeId::of::()); - let kind = match Self::lad_primitive_type_from_type_id(TypeId::of::()) { + let kind = match LadBMSPrimitiveKind::from_type_id(TypeId::of::()) { Some(primitive) => primitive, None => return self, }; @@ -530,14 +605,20 @@ impl<'t> LadFileBuilder<'t> { if let Some(lad_id) = self.type_id_mapping.get(&type_id) { return lad_id.clone(); } - let new_id = match self.type_registry.get_type_info(type_id) { - Some(info) => info.type_path_table().path().to_owned(), - None => format!("{type_id:?}"), + + let new_id = match LadBMSPrimitiveKind::from_type_id(type_id) { + Some(primitive) => primitive.lad_type_id(), + None => { + if let Some(info) = self.type_registry.get_type_info(type_id) { + LadTypeId::new_string_id(info.type_path_table().path().into()) + } else { + LadTypeId::new_string_id(format!("{type_id:?}").into()) + } + } }; - let lad_id = LadTypeId::new_string_id(new_id.into()); - self.type_id_mapping.insert(type_id, lad_id.clone()); - lad_id + self.type_id_mapping.insert(type_id, new_id.clone()); + new_id } fn lad_function_id_from_info(&mut self, function_info: &FunctionInfo) -> LadFunctionId { @@ -553,40 +634,6 @@ impl<'t> LadFileBuilder<'t> { LadFunctionId::new_string_id(format!("{}::{}", namespace_string, function_info.name)) } - /// We can assume that the types here will be either primitives - /// or reflect types, as the rest will be covered by typed wrappers - /// so just check - fn lad_primitive_type_from_type_id(type_id: TypeId) -> Option { - match_by_type!(match type_id { - i: bool => return Some(LadBMSPrimitiveKind::Bool), - i: isize => return Some(LadBMSPrimitiveKind::Isize), - i: i8 => return Some(LadBMSPrimitiveKind::I8), - i: i16 => return Some(LadBMSPrimitiveKind::I16), - i: i32 => return Some(LadBMSPrimitiveKind::I32), - i: i64 => return Some(LadBMSPrimitiveKind::I64), - i: i128 => return Some(LadBMSPrimitiveKind::I128), - i: usize => return Some(LadBMSPrimitiveKind::Usize), - i: u8 => return Some(LadBMSPrimitiveKind::U8), - i: u16 => return Some(LadBMSPrimitiveKind::U16), - i: u32 => return Some(LadBMSPrimitiveKind::U32), - i: u64 => return Some(LadBMSPrimitiveKind::U64), - i: u128 => return Some(LadBMSPrimitiveKind::U128), - i: f32 => return Some(LadBMSPrimitiveKind::F32), - i: f64 => return Some(LadBMSPrimitiveKind::F64), - i: char => return Some(LadBMSPrimitiveKind::Char), - i: &'static str => return Some(LadBMSPrimitiveKind::Str), - i: String => return Some(LadBMSPrimitiveKind::String), - i: OsString => return Some(LadBMSPrimitiveKind::OsString), - i: PathBuf => return Some(LadBMSPrimitiveKind::PathBuf), - i: FunctionCallContext => return Some(LadBMSPrimitiveKind::FunctionCallContext), - i: DynamicFunction => return Some(LadBMSPrimitiveKind::DynamicFunction), - i: DynamicFunctionMut => return Some(LadBMSPrimitiveKind::DynamicFunctionMut), - i: ReflectReference => return Some(LadBMSPrimitiveKind::ReflectReference) - }); - - None - } - fn lad_argument_type_from_through_type( &mut self, through_type: &ThroughTypeInfo, @@ -639,7 +686,7 @@ impl<'t> LadFileBuilder<'t> { ), }, ThroughTypeInfo::TypeInfo(type_info) => { - match Self::lad_primitive_type_from_type_id(type_info.type_id()) { + match LadBMSPrimitiveKind::from_type_id(type_info.type_id()) { Some(primitive) => LadArgumentKind::Primitive(primitive), None => LadArgumentKind::Unknown(self.lad_id_from_type_id(type_info.type_id())), } @@ -690,8 +737,6 @@ mod test { #[test] fn test_serializes_as_expected() { let mut type_registry = TypeRegistry::default(); - type_registry.register::(); - type_registry.register::(); #[derive(Reflect)] /// I am a struct diff --git a/crates/ladfile/test_assets/test.lad.json b/crates/ladfile/test_assets/test.lad.json index caa95c43d8..8a9a6ab71e 100644 --- a/crates/ladfile/test_assets/test.lad.json +++ b/crates/ladfile/test_assets/test.lad.json @@ -28,7 +28,7 @@ "type": "usize" }, { - "type": "alloc::string::String" + "type": "String" } ] } @@ -73,7 +73,7 @@ "type": "usize" }, { - "type": "alloc::string::String" + "type": "String" } ] } @@ -139,38 +139,34 @@ } }, "primitives": { - "TypeId(0x0b36ea25c1cf517efce182c726ea2190)": { - "kind": "pathBuf", - "documentation": "A heap allocated file path" - }, - "TypeId(0x1c306727557831f62320b5841ddc7eb3)": { + "DynamicFunction": { "kind": "dynamicFunction", "documentation": "A callable dynamic function" }, - "TypeId(0x7adbf8cf2ed263727e95f06e821c8654)": { - "kind": "osString", - "documentation": "A heap allocated OS string" - }, - "TypeId(0x7f945ad2d333d63863e3b6f35dfc0c5d)": { + "DynamicFunctionMut": { "kind": "dynamicFunctionMut", "documentation": "A stateful and callable dynamic function" }, - "TypeId(0xb98b1b7157a6417863eb502cd6cb5d6d)": { - "kind": "str", - "documentation": "A static string slice" - }, - "alloc::string::String": { - "kind": "string", - "documentation": "A heap allocated string" - }, - "bevy_mod_scripting_core::bindings::function::script_function::FunctionCallContext": { + "FunctionCallContext": { "kind": "functionCallContext", "documentation": "Function call context, if accepted by a function, means the function can access the world in arbitrary ways." }, - "bevy_mod_scripting_core::bindings::reference::ReflectReference": { + "OsString": { + "kind": "osString", + "documentation": "A heap allocated OS string" + }, + "PathBuf": { + "kind": "pathBuf", + "documentation": "A heap allocated file path" + }, + "ReflectReference": { "kind": "reflectReference", "documentation": "A reference to a reflectable type" }, + "String": { + "kind": "string", + "documentation": "A heap allocated string" + }, "bool": { "kind": "bool", "documentation": "A boolean value" @@ -211,6 +207,10 @@ "kind": "isize", "documentation": "A signed pointer-sized integer" }, + "str": { + "kind": "str", + "documentation": "A string slice" + }, "u128": { "kind": "u128", "documentation": "An unsigned 128-bit integer" diff --git a/tealr_doc_gen_config.json b/tealr_doc_gen_config.json deleted file mode 100644 index 819078d063..0000000000 --- a/tealr_doc_gen_config.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "doc_template": "Builtin", - "page_root": "", - "store_in": "CoreBevyAPI", - "name": "CoreBevyAPI", - "is_global": true, - "type_def_files": { - "runner": "Builtin", - "templates": { - "teal": { - "extension": ".d.tl", - "template": "Teal" - } - } - } -} \ No newline at end of file diff --git a/tlconfig.lua b/tlconfig.lua deleted file mode 100644 index 53c5e8adc8..0000000000 --- a/tlconfig.lua +++ /dev/null @@ -1,5 +0,0 @@ -return { - include_dir = { - "bevy_mod_scripting/", - } -} \ No newline at end of file From 6bf28bfe33a2a0c6fbdc9f65c13673e43d7357c9 Mon Sep 17 00:00:00 2001 From: makspll Date: Wed, 12 Feb 2025 11:18:51 +0000 Subject: [PATCH 8/8] normalize line endings --- crates/ladfile/src/lib.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/ladfile/src/lib.rs b/crates/ladfile/src/lib.rs index 459bbcdf26..964b06ca72 100644 --- a/crates/ladfile/src/lib.rs +++ b/crates/ladfile/src/lib.rs @@ -725,6 +725,11 @@ mod test { /// Set to true to put output into test_assets. const BLESS_TEST_FILE: bool = false; + /// normalize line endings etc.. + fn normalize_file_for_os(file: &mut String) { + *file = file.replace("\r\n", "\n"); + } + #[test] fn test_empty_lad_file_serializes_correctly() { let lad_file = LadFile::new(); @@ -799,7 +804,9 @@ mod test { .add_type::() .add_type_info(EnumType::type_info()) .build(); - let serialized = serialize_lad_file(&lad_file, true).unwrap(); + let mut serialized = serialize_lad_file(&lad_file, true).unwrap(); + + normalize_file_for_os(&mut serialized); if BLESS_TEST_FILE { let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); @@ -810,7 +817,8 @@ mod test { return; } - let expected = include_str!("../test_assets/test.lad.json"); + let mut expected = include_str!("../test_assets/test.lad.json").to_owned(); + normalize_file_for_os(&mut expected); assert_eq!( serialized.trim(),