Skip to content

Commit 2da36d5

Browse files
authored
feat: add global instances to LAD format (#283)
* feat: add global instances to LAD format * link to test data in readme
1 parent e6d0199 commit 2da36d5

File tree

4 files changed

+61
-249
lines changed

4 files changed

+61
-249
lines changed

crates/ladfile/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ repository = "https://github.com/makspll/bevy_mod_scripting"
99
homepage = "https://github.com/makspll/bevy_mod_scripting"
1010
keywords = ["bevy", "gamedev", "scripting", "format", "json"]
1111
categories = ["game-development", "parser-implementations"]
12+
include = ["readme.md", "/src", "/test_assets"]
1213
readme = "readme.md"
1314

1415
[dependencies]

crates/ladfile/readme.md

Lines changed: 1 addition & 242 deletions
Original file line numberDiff line numberDiff line change
@@ -9,245 +9,4 @@ A file format specifying the available exported:
99
For a `bevy` game engine project.
1010

1111
## Example
12-
13-
```json
14-
{
15-
"version": "0.1.0",
16-
"types": {
17-
"ladfile::test::EnumType": {
18-
"identifier": "EnumType",
19-
"crate": "ladfile",
20-
"path": "ladfile::test::EnumType",
21-
"layout": [
22-
{
23-
"kind": "Unit",
24-
"name": "Unit"
25-
},
26-
{
27-
"kind": "Struct",
28-
"name": "Struct",
29-
"fields": [
30-
{
31-
"name": "field",
32-
"type": "usize"
33-
}
34-
]
35-
},
36-
{
37-
"kind": "TupleStruct",
38-
"name": "TupleStruct",
39-
"fields": [
40-
{
41-
"type": "usize"
42-
},
43-
{
44-
"type": "alloc::string::String"
45-
}
46-
]
47-
}
48-
]
49-
},
50-
"ladfile::test::StructType<usize>": {
51-
"identifier": "StructType",
52-
"crate": "ladfile",
53-
"path": "ladfile::test::StructType<usize>",
54-
"generics": [
55-
{
56-
"type_id": "usize",
57-
"name": "T"
58-
}
59-
],
60-
"documentation": " I am a struct",
61-
"layout": {
62-
"kind": "Struct",
63-
"name": "StructType",
64-
"fields": [
65-
{
66-
"name": "field",
67-
"type": "usize"
68-
},
69-
{
70-
"name": "field2",
71-
"type": "usize"
72-
}
73-
]
74-
}
75-
},
76-
"ladfile::test::TupleStructType": {
77-
"identifier": "TupleStructType",
78-
"crate": "ladfile",
79-
"path": "ladfile::test::TupleStructType",
80-
"documentation": " I am a tuple test type",
81-
"layout": {
82-
"kind": "TupleStruct",
83-
"name": "TupleStructType",
84-
"fields": [
85-
{
86-
"type": "usize"
87-
},
88-
{
89-
"type": "alloc::string::String"
90-
}
91-
]
92-
}
93-
},
94-
"ladfile::test::UnitType": {
95-
"identifier": "UnitType",
96-
"crate": "ladfile",
97-
"path": "ladfile::test::UnitType",
98-
"documentation": " I am a unit test type",
99-
"layout": {
100-
"kind": "Struct",
101-
"name": "UnitType"
102-
}
103-
}
104-
},
105-
"functions": {
106-
"::hello_world": {
107-
"identifier": "hello_world",
108-
"arguments": [
109-
{
110-
"kind": {
111-
"primitive": "usize"
112-
},
113-
"name": "arg1"
114-
}
115-
],
116-
"return_type": "usize"
117-
},
118-
"ladfile::test::StructType<usize>::hello_world": {
119-
"identifier": "hello_world",
120-
"arguments": [
121-
{
122-
"kind": {
123-
"primitive": "reflectReference"
124-
},
125-
"name": "ref_"
126-
},
127-
{
128-
"kind": {
129-
"tuple": [
130-
{
131-
"primitive": "usize"
132-
},
133-
{
134-
"primitive": "string"
135-
}
136-
]
137-
},
138-
"name": "tuple"
139-
},
140-
{
141-
"kind": {
142-
"option": {
143-
"vec": {
144-
"ref": "ladfile::test::EnumType"
145-
}
146-
}
147-
},
148-
"name": "option_vec_ref_wrapper"
149-
}
150-
],
151-
"return_type": "usize"
152-
}
153-
},
154-
"primitives": {
155-
"TypeId(0x0b36ea25c1cf517efce182c726ea2190)": {
156-
"kind": "pathBuf",
157-
"documentation": "A heap allocated file path"
158-
},
159-
"TypeId(0x1c306727557831f62320b5841ddc7eb3)": {
160-
"kind": "dynamicFunction",
161-
"documentation": "A callable dynamic function"
162-
},
163-
"TypeId(0x7adbf8cf2ed263727e95f06e821c8654)": {
164-
"kind": "osString",
165-
"documentation": "A heap allocated OS string"
166-
},
167-
"TypeId(0x7f945ad2d333d63863e3b6f35dfc0c5d)": {
168-
"kind": "dynamicFunctionMut",
169-
"documentation": "A stateful and callable dynamic function"
170-
},
171-
"TypeId(0xb98b1b7157a6417863eb502cd6cb5d6d)": {
172-
"kind": "str",
173-
"documentation": "A static string slice"
174-
},
175-
"alloc::string::String": {
176-
"kind": "string",
177-
"documentation": "A heap allocated string"
178-
},
179-
"bevy_mod_scripting_core::bindings::function::script_function::FunctionCallContext": {
180-
"kind": "functionCallContext",
181-
"documentation": "Function call context, if accepted by a function, means the function can access the world in arbitrary ways."
182-
},
183-
"bevy_mod_scripting_core::bindings::reference::ReflectReference": {
184-
"kind": "reflectReference",
185-
"documentation": "A reference to a reflectable type"
186-
},
187-
"bool": {
188-
"kind": "bool",
189-
"documentation": "A boolean value"
190-
},
191-
"char": {
192-
"kind": "char",
193-
"documentation": "An 8-bit character"
194-
},
195-
"f32": {
196-
"kind": "f32",
197-
"documentation": "A 32-bit floating point number"
198-
},
199-
"f64": {
200-
"kind": "f64",
201-
"documentation": "A 64-bit floating point number"
202-
},
203-
"i128": {
204-
"kind": "i128",
205-
"documentation": "A signed 128-bit integer"
206-
},
207-
"i16": {
208-
"kind": "i16",
209-
"documentation": "A signed 16-bit integer"
210-
},
211-
"i32": {
212-
"kind": "i32",
213-
"documentation": "A signed 32-bit integer"
214-
},
215-
"i64": {
216-
"kind": "i64",
217-
"documentation": "A signed 64-bit integer"
218-
},
219-
"i8": {
220-
"kind": "i8",
221-
"documentation": "A signed 8-bit integer"
222-
},
223-
"isize": {
224-
"kind": "isize",
225-
"documentation": "A signed pointer-sized integer"
226-
},
227-
"u128": {
228-
"kind": "u128",
229-
"documentation": "An unsigned 128-bit integer"
230-
},
231-
"u16": {
232-
"kind": "u16",
233-
"documentation": "An unsigned 16-bit integer"
234-
},
235-
"u32": {
236-
"kind": "u32",
237-
"documentation": "An unsigned 32-bit integer"
238-
},
239-
"u64": {
240-
"kind": "u64",
241-
"documentation": "An unsigned 64-bit integer"
242-
},
243-
"u8": {
244-
"kind": "u8",
245-
"documentation": "An unsigned 8-bit integer"
246-
},
247-
"usize": {
248-
"kind": "usize",
249-
"documentation": "An unsigned pointer-sized integer"
250-
}
251-
}
252-
}
253-
```
12+
See an example of a `LAD` file [here](./test_assets/test.lad.json)

crates/ladfile/src/lib.rs

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,19 @@ use bevy_reflect::{
1515
use indexmap::IndexMap;
1616
use std::{any::TypeId, borrow::Cow, collections::HashMap, ffi::OsString, path::PathBuf};
1717

18-
const LAD_VERSION: &str = "0.1.0";
18+
/// The current version of the LAD_VERSION format supported by this library.
19+
/// Earlier versions are not guaranteed to be supported.
20+
const LAD_VERSION: &str = env!("CARGO_PKG_VERSION");
1921

2022
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
2123
/// A Language Agnostic Declaration (LAD) file.
2224
pub struct LadFile {
2325
/// The version of the LAD file format used.
2426
pub version: Cow<'static, str>,
2527

28+
/// The global instances defined in the LAD file.
29+
pub globals: IndexMap<Cow<'static, str>, LadInstance>,
30+
2631
/// The types defined in the LAD file.
2732
pub types: IndexMap<LadTypeId, LadType>,
2833

@@ -38,6 +43,7 @@ impl LadFile {
3843
pub fn new() -> Self {
3944
Self {
4045
version: LAD_VERSION.into(),
46+
globals: IndexMap::new(),
4147
types: IndexMap::new(),
4248
functions: IndexMap::new(),
4349
primitives: IndexMap::new(),
@@ -51,6 +57,19 @@ impl Default for LadFile {
5157
}
5258
}
5359

60+
/// A LAD global instance
61+
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
62+
pub struct LadInstance {
63+
/// The type of the instance
64+
pub type_id: LadTypeId,
65+
66+
/// whether the instance is static or not
67+
///
68+
/// static instances do not support method call syntax on them. I.e. only functions without a self parameter can be called on them.
69+
/// They also do not support field access syntax.
70+
pub is_static: bool,
71+
}
72+
5473
#[derive(
5574
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
5675
)]
@@ -432,6 +451,24 @@ impl<'t> LadFileBuilder<'t> {
432451
self
433452
}
434453

454+
/// Add a global instance to the LAD file.
455+
///
456+
/// Requires the type to be registered via [`Self::add_type`] or [`Self::add_type_info`] first to provide rich type information.
457+
///
458+
/// If `is_static` is true, the instance will be treated as a static instance
459+
/// and hence not support method call syntax or method calls (i.e. only functions without a self parameter can be called on them).
460+
pub fn add_instance<T: 'static>(
461+
&mut self,
462+
key: impl Into<Cow<'static, str>>,
463+
is_static: bool,
464+
) -> &mut Self {
465+
let type_id = self.lad_id_from_type_id(TypeId::of::<T>());
466+
self.file
467+
.globals
468+
.insert(key.into(), LadInstance { type_id, is_static });
469+
self
470+
}
471+
435472
/// Add a type definition to the LAD file.
436473
///
437474
/// Equivalent to calling [`Self::add_type_info`] with `T::type_info()`.
@@ -726,7 +763,7 @@ mod test {
726763
const BLESS_TEST_FILE: bool = false;
727764

728765
/// normalize line endings etc..
729-
fn normalize_file_for_os(file: &mut String) {
766+
fn normalize_file(file: &mut String) {
730767
*file = file.replace("\r\n", "\n");
731768
}
732769

@@ -794,7 +831,7 @@ mod test {
794831
.get_function_info("hello_world".into(), GlobalNamespace::into_namespace())
795832
.with_arg_names(&["arg1"]);
796833

797-
let lad_file = LadFileBuilder::new(&type_registry)
834+
let mut lad_file = LadFileBuilder::new(&type_registry)
798835
.set_sorted(true)
799836
.add_function_info(function_info)
800837
.add_function_info(global_function_info)
@@ -803,10 +840,15 @@ mod test {
803840
.add_type::<UnitType>()
804841
.add_type::<TupleStructType>()
805842
.add_type_info(EnumType::type_info())
843+
.add_instance::<StructType<usize>>("my_static_instance", true)
844+
.add_instance::<UnitType>("my_non_static_instance", false)
806845
.build();
846+
847+
// normalize the version so we don't have to update it every time
848+
lad_file.version = "{{version}}".into();
807849
let mut serialized = serialize_lad_file(&lad_file, true).unwrap();
808850

809-
normalize_file_for_os(&mut serialized);
851+
normalize_file(&mut serialized);
810852

811853
if BLESS_TEST_FILE {
812854
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
@@ -818,7 +860,7 @@ mod test {
818860
}
819861

820862
let mut expected = include_str!("../test_assets/test.lad.json").to_owned();
821-
normalize_file_for_os(&mut expected);
863+
normalize_file(&mut expected);
822864

823865
assert_eq!(
824866
serialized.trim(),
@@ -833,6 +875,6 @@ mod test {
833875
fn test_asset_deserializes_correctly() {
834876
let asset = include_str!("../test_assets/test.lad.json");
835877
let deserialized = parse_lad_file(asset).unwrap();
836-
assert_eq!(deserialized.version, LAD_VERSION);
878+
assert_eq!(deserialized.version, "{{version}}");
837879
}
838880
}

crates/ladfile/test_assets/test.lad.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
{
2-
"version": "0.1.0",
2+
"version": "{{version}}",
3+
"globals": {
4+
"my_static_instance": {
5+
"type_id": "ladfile::test::StructType<usize>",
6+
"is_static": true
7+
},
8+
"my_non_static_instance": {
9+
"type_id": "ladfile::test::UnitType",
10+
"is_static": false
11+
}
12+
},
313
"types": {
414
"ladfile::test::EnumType": {
515
"identifier": "EnumType",

0 commit comments

Comments
 (0)