From 9effbab1c63004ea4174400bbe754a97e713a69a Mon Sep 17 00:00:00 2001 From: makspll Date: Wed, 12 Feb 2025 18:17:10 +0000 Subject: [PATCH 1/3] feat: add global instances to LAD format --- crates/ladfile/src/lib.rs | 52 +++++++++++++++++++++--- crates/ladfile/test_assets/test.lad.json | 12 +++++- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/crates/ladfile/src/lib.rs b/crates/ladfile/src/lib.rs index 964b06ca72..d393d24638 100644 --- a/crates/ladfile/src/lib.rs +++ b/crates/ladfile/src/lib.rs @@ -15,7 +15,9 @@ use bevy_reflect::{ use indexmap::IndexMap; use std::{any::TypeId, borrow::Cow, collections::HashMap, ffi::OsString, path::PathBuf}; -const LAD_VERSION: &str = "0.1.0"; +/// The current version of the LAD_VERSION format supported by this library. +/// Earlier versions are not guaranteed to be supported. +const LAD_VERSION: &str = env!("CARGO_PKG_VERSION"); #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] /// A Language Agnostic Declaration (LAD) file. @@ -23,6 +25,9 @@ pub struct LadFile { /// The version of the LAD file format used. pub version: Cow<'static, str>, + /// The global instances defined in the LAD file. + pub globals: IndexMap, LadInstance>, + /// The types defined in the LAD file. pub types: IndexMap, @@ -38,6 +43,7 @@ impl LadFile { pub fn new() -> Self { Self { version: LAD_VERSION.into(), + globals: IndexMap::new(), types: IndexMap::new(), functions: IndexMap::new(), primitives: IndexMap::new(), @@ -51,6 +57,19 @@ impl Default for LadFile { } } +/// A LAD global instance +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct LadInstance { + /// The type of the instance + pub type_id: LadTypeId, + + /// whether the instance is static or not + /// + /// static instances do not support method call syntax on them. I.e. only functions without a self parameter can be called on them. + /// They also do not support field access syntax. + pub is_static: bool, +} + #[derive( Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, )] @@ -432,6 +451,24 @@ impl<'t> LadFileBuilder<'t> { self } + /// Add a global instance to the LAD file. + /// + /// Requires the type to be registered via [`Self::add_type`] or [`Self::add_type_info`] first to provide rich type information. + /// + /// If `is_static` is true, the instance will be treated as a static instance + /// and hence not support method call syntax or method calls (i.e. only functions without a self parameter can be called on them). + pub fn add_instance( + &mut self, + key: impl Into>, + is_static: bool, + ) -> &mut Self { + let type_id = self.lad_id_from_type_id(TypeId::of::()); + self.file + .globals + .insert(key.into(), LadInstance { type_id, is_static }); + self + } + /// Add a type definition to the LAD file. /// /// Equivalent to calling [`Self::add_type_info`] with `T::type_info()`. @@ -726,7 +763,7 @@ mod test { const BLESS_TEST_FILE: bool = false; /// normalize line endings etc.. - fn normalize_file_for_os(file: &mut String) { + fn normalize_file(file: &mut String) { *file = file.replace("\r\n", "\n"); } @@ -794,7 +831,7 @@ mod test { .get_function_info("hello_world".into(), GlobalNamespace::into_namespace()) .with_arg_names(&["arg1"]); - let lad_file = LadFileBuilder::new(&type_registry) + let mut lad_file = LadFileBuilder::new(&type_registry) .set_sorted(true) .add_function_info(function_info) .add_function_info(global_function_info) @@ -803,10 +840,15 @@ mod test { .add_type::() .add_type::() .add_type_info(EnumType::type_info()) + .add_instance::>("my_static_instance", true) + .add_instance::("my_non_static_instance", false) .build(); + + // normalize the version so we don't have to update it every time + lad_file.version = "{{version}}".into(); let mut serialized = serialize_lad_file(&lad_file, true).unwrap(); - normalize_file_for_os(&mut serialized); + normalize_file(&mut serialized); if BLESS_TEST_FILE { let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); @@ -818,7 +860,7 @@ mod test { } let mut expected = include_str!("../test_assets/test.lad.json").to_owned(); - normalize_file_for_os(&mut expected); + normalize_file(&mut expected); assert_eq!( serialized.trim(), diff --git a/crates/ladfile/test_assets/test.lad.json b/crates/ladfile/test_assets/test.lad.json index 8a9a6ab71e..feee166ac8 100644 --- a/crates/ladfile/test_assets/test.lad.json +++ b/crates/ladfile/test_assets/test.lad.json @@ -1,5 +1,15 @@ { - "version": "0.1.0", + "version": "{{version}}", + "globals": { + "my_static_instance": { + "type_id": "ladfile::test::StructType", + "is_static": true + }, + "my_non_static_instance": { + "type_id": "ladfile::test::UnitType", + "is_static": false + } + }, "types": { "ladfile::test::EnumType": { "identifier": "EnumType", From 5b4e6a4d125fb662f21bbad09527f1784ac86e10 Mon Sep 17 00:00:00 2001 From: makspll Date: Wed, 12 Feb 2025 18:25:43 +0000 Subject: [PATCH 2/3] link to test data in readme --- crates/ladfile/Cargo.toml | 1 + crates/ladfile/readme.md | 243 +------------------------------------- 2 files changed, 2 insertions(+), 242 deletions(-) diff --git a/crates/ladfile/Cargo.toml b/crates/ladfile/Cargo.toml index ef6fb369a5..9ce1d7b334 100644 --- a/crates/ladfile/Cargo.toml +++ b/crates/ladfile/Cargo.toml @@ -9,6 +9,7 @@ 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"] +include = ["readme.md", "/src", "/test_assets"] readme = "readme.md" [dependencies] diff --git a/crates/ladfile/readme.md b/crates/ladfile/readme.md index ed86ada64b..df8b3790fa 100644 --- a/crates/ladfile/readme.md +++ b/crates/ladfile/readme.md @@ -9,245 +9,4 @@ A file format specifying the available exported: 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" - } - } -} -``` +See an example of a `LAD` file [here](./test_assets/test.lad.json) \ No newline at end of file From d0cab2642000d3c88bf397be2a4856ed9905433b Mon Sep 17 00:00:00 2001 From: Maksymilian Mozolewski Date: Wed, 12 Feb 2025 19:20:55 +0000 Subject: [PATCH 3/3] Update lib.rs --- 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 d393d24638..103b7ebf21 100644 --- a/crates/ladfile/src/lib.rs +++ b/crates/ladfile/src/lib.rs @@ -875,6 +875,6 @@ mod 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); + assert_eq!(deserialized.version, "{{version}}"); } }