Skip to content

Commit 29ddde3

Browse files
bors[bot]Bromeon
andauthored
Merge #811
811: Simplify module structure II r=Bromeon a=Bromeon This PR is a continuation of #788 and addresses the remaining, somewhat ambitious tasks for module cleanup. Goals: * Every symbol appears at most once in prelude * Every symbol appears at exactly once outside prelude * 2-3 modules (inside the crate) are the maximum nesting depth * Modules named according to related functionality from user point of view Changes: 1. `nativescript` module * Rename to `export`. Rationale: "native script" is quite a wide term, while most the module's current functionality is directly related to _exporting_ symbols from Rust. In practice, godot-rust is always (?) used as a native script. Other potential use cases, as a pure Godot API library or with native_calls, seem to be the exception, if at all. * Along with renaming, the `nativescript` feature is removed. * Nested symbols in `export::{properties, methods}` are moved one level up. * As a result, we can avoid very long qualifiers and multiple candidates for `use` statements. * `nativescript::init::property::hint::EnumHint` -> `export::hint::EnumHint` * `nativescript::export::method::MethodBuilder` -> `export::MethodBuilder` 1. `api` module * Remove inner types like `api::area::Area`, as they are already present in `api`. * Remove all modules which would then become empty. * Create doc links between class (`Camera2D`) and related module (`camera_2d`). 1. Smaller top-level modules * Add `init` (previously part of `nativescript`). * Add `profiler` (previously part of `nativescript`). * Extend `log` with related macros. * Remove `macros` and distribute its symbols to the most fitting API. 1. `prelude` module * Remove a few macros (`godot_gdnative_init` etc.) from the prelude, suggesting that `godot_init` should be used. * `user_data` symbols are accessible through `prelude::user_data` instead of `prelude` directly. This mirrors common usage in examples. 1. `core_types` module No changes in this PR; see PR discussion for reasons and potential alternatives. Co-authored-by: Jan Haller <[email protected]>
2 parents 06110f9 + dded6f6 commit 29ddde3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+894
-844
lines changed

bindings_generator/src/api.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ impl GodotClass {
160160
pub fn is_getter(&self, name: &str) -> bool {
161161
self.properties.iter().any(|p| p.getter == name)
162162
}
163+
164+
/// Whether there is a snake_case module containing related symbols (nested types in C++)
165+
pub fn has_related_module(&self) -> bool {
166+
!self.enums.is_empty()
167+
}
163168
}
164169

165170
pub type ConstantName = String;
@@ -406,9 +411,8 @@ impl Ty {
406411
}
407412
}
408413
ty => {
409-
let module = format_ident!("{}", module_name_from_class_name(ty));
410414
let ty = format_ident!("{}", ty);
411-
Ty::Object(syn::parse_quote! { crate::generated::#module::#ty })
415+
Ty::Object(syn::parse_quote! { crate::generated::#ty })
412416
}
413417
}
414418
}

bindings_generator/src/classes.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,22 @@ use quote::{format_ident, quote};
99

1010
use std::collections::HashMap;
1111

12-
pub(crate) fn generate_class_struct(class: &GodotClass) -> TokenStream {
12+
pub(crate) fn generate_class_struct(class: &GodotClass, class_doc: TokenStream) -> TokenStream {
1313
let class_name = format_ident!("{}", &class.name);
1414

1515
// dead_code: 'this' might not be read
16+
// mod private: hide the type in the #module_name module, export it only in gdnative::api
1617
quote! {
17-
#[allow(non_camel_case_types)]
18-
#[derive(Debug)]
19-
pub struct #class_name {
20-
#[allow(dead_code)]
21-
this: RawObject<Self>,
18+
pub(crate) mod private {
19+
#class_doc
20+
#[allow(non_camel_case_types)]
21+
#[derive(Debug)]
22+
pub struct #class_name {
23+
#[allow(dead_code)]
24+
pub(crate) this: super::RawObject<Self>,
25+
}
2226
}
27+
use private::#class_name;
2328
}
2429
}
2530

bindings_generator/src/documentation.rs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,43 +12,56 @@ pub fn class_doc_link(class: &GodotClass) -> String {
1212

1313
pub fn official_doc_url(class: &GodotClass) -> String {
1414
format!(
15-
"https://godot.readthedocs.io/en/latest/classes/class_{lower_case}.html",
15+
"https://godot.readthedocs.io/en/stable/classes/class_{lower_case}.html",
1616
lower_case = class.name.to_lowercase(),
1717
)
1818
}
1919

20+
pub fn generate_module_doc(class: &GodotClass) -> TokenStream {
21+
let module_doc = format!(
22+
"This module contains types related to the API class [`{m}`][super::{m}].",
23+
m = class.name
24+
);
25+
26+
quote! {
27+
#![doc=#module_doc]
28+
}
29+
}
30+
2031
pub fn generate_class_documentation(api: &Api, class: &GodotClass) -> TokenStream {
2132
let has_parent = !class.base_class.is_empty();
2233
let singleton_str = if class.singleton { "singleton " } else { "" };
23-
let ownership_type = if class.is_refcounted() {
24-
"reference counted"
34+
let memory_type = if class.is_refcounted() {
35+
"reference-counted"
2536
} else {
26-
"unsafe"
37+
"manually managed"
2738
};
2839

29-
let summary_doc = if &class.name == "Reference" {
40+
let mut summary_doc = if &class.name == "Reference" {
3041
"Base class of all reference-counted types. Inherits `Object`.".into()
3142
} else if &class.name == "Object" {
32-
"The base class of most Godot classes.".into()
43+
"The base class of all classes in the Godot hierarchy.".into()
3344
} else if has_parent {
3445
format!(
35-
"`{api_type} {singleton}class {name}` inherits `{base_class}` ({ownership_type}).",
46+
"`{api_type} {singleton}class {name}` inherits `{base_class}` ({memory_type}).",
3647
api_type = class.api_type,
3748
name = class.name,
3849
base_class = class.base_class,
39-
ownership_type = ownership_type,
40-
singleton = singleton_str
50+
memory_type = memory_type,
51+
singleton = singleton_str,
4152
)
4253
} else {
4354
format!(
44-
"`{api_type} {singleton}class {name}` ({ownership_type}).",
55+
"`{api_type} {singleton}class {name}` ({memory_type})",
4556
api_type = class.api_type,
4657
name = class.name,
47-
ownership_type = ownership_type,
58+
memory_type = memory_type,
4859
singleton = singleton_str,
4960
)
5061
};
5162

63+
append_related_module(&mut summary_doc, class);
64+
5265
let official_docs = format!(
5366
r#"## Official documentation
5467
@@ -66,7 +79,7 @@ The lifetime of this object is automatically managed through reference counting.
6679
format!(
6780
r#"## Memory management
6881
69-
Non reference counted objects such as the ones of this type are usually owned by the engine.
82+
Non-reference-counted objects, such as the ones of this type, are usually owned by the engine.
7083
7184
`{name}` is a reference-only type. Persistent references can
7285
only exist in the unsafe `Ref<{name}>` form.
@@ -113,7 +126,7 @@ This class is used to interact with Godot's editor."#
113126
let safety_doc = r#"
114127
## Safety
115128
116-
All types in the Godot API have "interior mutability" in Rust parlance.
129+
All types in the Godot API have _interior mutability_ in Rust parlance.
117130
To enforce that the official [thread-safety guidelines][thread-safety] are
118131
followed, the typestate pattern is used in the `Ref` and `TRef` smart pointers,
119132
and the `Instance` API. The typestate `Access` in these types tracks whether the
@@ -145,3 +158,16 @@ fn list_base_classes(output: &mut impl Write, api: &Api, parent_name: &str) -> G
145158

146159
Ok(())
147160
}
161+
162+
// If present, links to the module with related (C++: nested) types.
163+
fn append_related_module(string: &mut String, class: &GodotClass) {
164+
use std::fmt::Write;
165+
if class.has_related_module() {
166+
write!(
167+
string,
168+
"\n\nThis class has related types in the [`{m}`][super::{m}] module.",
169+
m = class.module()
170+
)
171+
.expect("append to string via write!");
172+
}
173+
}

bindings_generator/src/lib.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,20 @@ use std::io;
3838

3939
pub type GeneratorResult<T = ()> = Result<T, io::Error>;
4040

41-
pub struct BindingResult {
42-
pub class_bindings: HashMap<String, TokenStream>,
41+
pub struct BindingResult<'a> {
42+
pub class_bindings: Vec<(&'a GodotClass, TokenStream)>,
4343
pub icalls: TokenStream,
4444
}
4545

46-
pub fn generate_bindings(api: &Api, docs: Option<&GodotXmlDocs>) -> BindingResult {
46+
pub fn generate_bindings<'a>(api: &'a Api, docs: Option<&GodotXmlDocs>) -> BindingResult<'a> {
4747
let mut icalls = HashMap::new();
4848

4949
let class_bindings = api
5050
.classes
5151
.iter()
5252
.map(|class| {
5353
(
54-
class.name.clone(),
54+
class,
5555
generate_class_bindings(api, class, &mut icalls, docs),
5656
)
5757
})
@@ -84,9 +84,9 @@ fn generate_class_bindings(
8484
) -> TokenStream {
8585
// types and methods
8686
let types_and_methods = {
87-
let documentation = generate_class_documentation(api, class);
88-
89-
let class_struct = generate_class_struct(class);
87+
let module_doc = generate_module_doc(class);
88+
let class_doc = generate_class_documentation(api, class);
89+
let class_struct = generate_class_struct(class, class_doc);
9090

9191
let enums = generate_enums(class);
9292

@@ -99,7 +99,7 @@ fn generate_class_bindings(
9999
let class_impl = generate_class_impl(class, icalls, docs);
100100

101101
quote! {
102-
#documentation
102+
#module_doc
103103
#class_struct
104104
#enums
105105
#constants
@@ -196,17 +196,23 @@ pub(crate) mod test_prelude {
196196

197197
#[test]
198198
fn sanity_test_generated_code() {
199+
// Tests whether each generated snippet individually constitutes a valid AST representation of Rust code
200+
199201
let api = Api::new(include_str!("../../gdnative-bindings/api.json"));
200202
let mut buffer = BufWriter::new(Vec::with_capacity(16384));
201203
for class in &api.classes {
202204
let mut icalls = HashMap::new();
203205

204-
let code = generate_class_documentation(&api, &class);
206+
let code = generate_module_doc(&class);
207+
write!(&mut buffer, "{}", code).unwrap();
208+
validate_and_clear_buffer!(buffer);
209+
210+
let class_doc = generate_class_documentation(&api, &class);
205211
write!(&mut buffer, "{}", code).unwrap();
206-
write!(&mut buffer, "{}", quote! { struct Docs {} }).unwrap();
212+
write!(&mut buffer, "{}", quote! { struct StructWithDocs {} }).unwrap();
207213
validate_and_clear_buffer!(buffer);
208214

209-
let code = generate_class_struct(&class);
215+
let code = generate_class_struct(&class, class_doc);
210216
write!(&mut buffer, "{}", code).unwrap();
211217
validate_and_clear_buffer!(buffer);
212218

bindings_generator/src/special_methods.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,10 @@ pub fn generate_deref_impl(class: &GodotClass) -> TokenStream {
154154
);
155155

156156
let class_name = format_ident!("{}", class.name);
157-
let base_class_module = format_ident!("{}", class.base_class_module());
158157
let base_class = format_ident!("{}", class.base_class);
159158

160159
let qualified_base_class = quote! {
161-
crate::generated::#base_class_module::#base_class
160+
crate::generated::#base_class
162161
};
163162

164163
quote! {
@@ -190,11 +189,10 @@ pub fn generate_sub_class_impls<'a>(api: &'a Api, mut class: &'a GodotClass) ->
190189
let mut tokens = TokenStream::new();
191190

192191
while let Some(base_class) = class.base_class(api) {
193-
let base_class_module = format_ident!("{}", base_class.module());
194192
let base_class_ident = format_ident!("{}", base_class.name);
195193

196194
tokens.extend(quote! {
197-
unsafe impl SubClass<crate::generated::#base_class_module::#base_class_ident> for #class_name {}
195+
unsafe impl SubClass<crate::generated::#base_class_ident> for #class_name {}
198196
});
199197

200198
class = base_class;

examples/array_export/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use gdnative::nativescript::export::property::hint::{ArrayHint, IntHint, RangeHint};
1+
use gdnative::export::hint::{ArrayHint, IntHint, RangeHint};
22
use gdnative::prelude::*;
33

44
#[derive(NativeClass)]

examples/spinning_cube/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use gdnative::api::MeshInstance;
22
use gdnative::prelude::*;
33

4-
use gdnative::nativescript::export::property::{EnumHint, IntHint, StringHint};
4+
use gdnative::export::hint::{EnumHint, IntHint, StringHint};
55

66
#[derive(gdnative::derive::NativeClass)]
77
#[inherit(MeshInstance)]

gdnative-async/src/method.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ use std::sync::Arc;
55
use futures_task::{LocalFutureObj, LocalSpawn, SpawnError};
66

77
use gdnative_core::core_types::{ToVariant, Variant};
8+
use gdnative_core::export::{Method, NativeClass, Varargs};
89
use gdnative_core::log::{self, Site};
9-
use gdnative_core::nativescript::export::{Method, Varargs};
10-
use gdnative_core::nativescript::{NativeClass, RefInstance};
1110
use gdnative_core::object::ownership::Shared;
11+
use gdnative_core::object::RefInstance;
1212

1313
use crate::rt::Context;
1414

gdnative-async/src/rt.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
11
use std::marker::PhantomData;
22

3+
use func_state::FuncState;
34
use gdnative_bindings::Object;
4-
use gdnative_core::object::SubClass;
5-
65
use gdnative_core::core_types::{GodotError, Variant};
7-
use gdnative_core::nativescript::export::InitHandle;
8-
use gdnative_core::nativescript::{Instance, RefInstance};
6+
use gdnative_core::init::InitHandle;
97
use gdnative_core::object::ownership::Shared;
10-
use gdnative_core::object::TRef;
8+
use gdnative_core::object::{Instance, RefInstance, SubClass, TRef};
119

1210
use crate::future;
1311

1412
mod bridge;
1513
mod func_state;
1614

17-
use func_state::FuncState;
18-
1915
/// Context for creating `yield`-like futures in async methods.
2016
pub struct Context {
2117
func_state: Instance<FuncState, Shared>,

gdnative-async/src/rt/bridge.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ use parking_lot::Mutex;
55

66
use gdnative_bindings::{Object, Reference};
77
use gdnative_core::core_types::{GodotError, Variant, VariantArray};
8+
use gdnative_core::export::user_data::{ArcData, Map};
9+
use gdnative_core::export::{ClassBuilder, Method, NativeClass, NativeClassMethods, Varargs};
810
use gdnative_core::godot_site;
9-
use gdnative_core::nativescript::export::method::{Method, Varargs};
10-
use gdnative_core::nativescript::export::ClassBuilder;
11-
use gdnative_core::nativescript::user_data::{ArcData, Map};
12-
use gdnative_core::nativescript::{Instance, NativeClass, NativeClassMethods, RefInstance};
13-
use gdnative_core::object::{ownership::Shared, TRef};
11+
use gdnative_core::object::ownership::Shared;
12+
use gdnative_core::object::{Instance, RefInstance, TRef};
1413

1514
use crate::future::Resume;
1615

gdnative-async/src/rt/func_state.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
use gdnative_bindings::Reference;
22
use gdnative_core::core_types::{ToVariant, Variant, VariantType};
3-
use gdnative_core::godot_site;
4-
use gdnative_core::nativescript::export::method::StaticArgs;
5-
use gdnative_core::nativescript::export::method::StaticArgsMethod;
6-
use gdnative_core::nativescript::export::{
7-
ClassBuilder, ExportInfo, PropertyUsage, Signal, SignalArgument,
3+
use gdnative_core::export::user_data::{LocalCellData, Map, MapMut};
4+
use gdnative_core::export::{
5+
ClassBuilder, ExportInfo, NativeClass, NativeClassMethods, PropertyUsage, Signal,
6+
SignalArgument, StaticArgs, StaticArgsMethod,
87
};
9-
use gdnative_core::nativescript::user_data::LocalCellData;
10-
use gdnative_core::nativescript::user_data::{Map, MapMut};
11-
use gdnative_core::nativescript::{Instance, NativeClass, NativeClassMethods, RefInstance};
8+
use gdnative_core::godot_site;
129
use gdnative_core::object::ownership::{Shared, Unique};
10+
use gdnative_core::object::{Instance, RefInstance};
1311
use gdnative_derive::FromVarargs;
1412

1513
use crate::future::Resume;

0 commit comments

Comments
 (0)