Skip to content

Commit bfc3a98

Browse files
authored
Merge pull request #594 from godot-rust/qol/core-move
godot-core: move some modules into their own files
2 parents cd652b7 + eef4154 commit bfc3a98

File tree

11 files changed

+444
-422
lines changed

11 files changed

+444
-422
lines changed

godot-core/src/deprecated.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (c) godot-rust; Bromeon and contributors.
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
6+
*/
7+
8+
// ------------------------------------------------------------------------------------------------------------------------------------------
9+
// Compatibility
10+
11+
// Code generated by Rust derive macros cannot cause any deprecation warnings, due to questionable "feature"
12+
// https://github.com/rust-lang/rust/pull/58994. Fortunately, an extra layer of indirection solves most problems: we generate a declarative
13+
// macro that itself isn't deprecated, but _its_ expansion is. Since the expansion happens in a later step, the warning is emitted.
14+
15+
#[inline(always)]
16+
#[deprecated = "#[base] is no longer needed; Base<T> is recognized directly. \n\
17+
More information on https://github.com/godot-rust/gdext/pull/577."]
18+
pub const fn base_attribute() {}
19+
20+
#[macro_export]
21+
macro_rules! emit_deprecated_warning {
22+
($warning_fn:ident) => {
23+
const _: () = $crate::__deprecated::$warning_fn();
24+
};
25+
}
26+
27+
pub use crate::emit_deprecated_warning;

godot-core/src/lib.rs

+6-157
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ pub mod log;
1515
pub mod obj;
1616
pub mod property;
1717

18+
#[doc(hidden)]
19+
#[path = "deprecated.rs"]
20+
pub mod __deprecated;
21+
#[doc(hidden)]
22+
pub mod private;
23+
1824
pub use godot_ffi as sys;
1925
#[doc(hidden)]
2026
pub use godot_ffi::out;
@@ -44,163 +50,6 @@ pub mod engine;
4450
mod gen;
4551

4652

47-
#[doc(hidden)]
48-
pub mod private {
49-
use std::sync::{Arc, Mutex};
50-
51-
pub use crate::gen::classes::class_macros;
52-
pub use crate::registry::{callbacks, ClassPlugin, ErasedRegisterFn, PluginItem};
53-
pub use crate::storage::{as_storage, Storage};
54-
pub use sys::out;
55-
56-
use crate::{log, sys};
57-
58-
// If someone forgets #[godot_api], this causes a compile error, rather than virtual functions not being called at runtime.
59-
#[allow(non_camel_case_types)]
60-
pub trait You_forgot_the_attribute__godot_api {}
61-
62-
sys::plugin_registry!(pub __GODOT_PLUGIN_REGISTRY: ClassPlugin);
63-
64-
pub(crate) fn iterate_plugins(mut visitor: impl FnMut(&ClassPlugin)) {
65-
sys::plugin_foreach!(__GODOT_PLUGIN_REGISTRY; visitor);
66-
}
67-
68-
pub use crate::obj::rtti::ObjectRtti;
69-
70-
pub struct ClassConfig {
71-
pub is_tool: bool,
72-
}
73-
74-
pub fn is_class_inactive(is_tool: bool) -> bool {
75-
if is_tool {
76-
return false;
77-
}
78-
79-
// SAFETY: only invoked after global library initialization.
80-
let global_config = unsafe { sys::config() };
81-
let is_editor = || crate::engine::Engine::singleton().is_editor_hint();
82-
83-
global_config.tool_only_in_editor //.
84-
&& global_config.is_editor_or_init(is_editor)
85-
}
86-
87-
pub fn print_panic(err: Box<dyn std::any::Any + Send>) {
88-
if let Some(s) = err.downcast_ref::<&'static str>() {
89-
print_panic_message(s);
90-
} else if let Some(s) = err.downcast_ref::<String>() {
91-
print_panic_message(s.as_str());
92-
} else {
93-
log::godot_error!("Rust panic of type ID {:?}", err.type_id());
94-
}
95-
}
96-
97-
pub fn auto_init<T>(l: &mut crate::obj::OnReady<T>) {
98-
l.init_auto();
99-
}
100-
101-
fn print_panic_message(msg: &str) {
102-
// If the message contains newlines, print all of the lines after a line break, and indent them.
103-
let lbegin = "\n ";
104-
let indented = msg.replace('\n', lbegin);
105-
106-
if indented.len() != msg.len() {
107-
log::godot_error!("Panic msg:{lbegin}{indented}");
108-
} else {
109-
log::godot_error!("Panic msg: {msg}");
110-
}
111-
}
112-
113-
struct GodotPanicInfo {
114-
line: u32,
115-
file: String,
116-
//backtrace: Backtrace, // for future use
117-
}
118-
119-
/// Executes `code`. If a panic is thrown, it is caught and an error message is printed to Godot.
120-
///
121-
/// Returns `None` if a panic occurred, and `Some(result)` with the result of `code` otherwise.
122-
#[must_use]
123-
pub fn handle_panic<E, F, R, S>(error_context: E, code: F) -> Option<R>
124-
where
125-
E: FnOnce() -> S,
126-
F: FnOnce() -> R + std::panic::UnwindSafe,
127-
S: std::fmt::Display,
128-
{
129-
let info: Arc<Mutex<Option<GodotPanicInfo>>> = Arc::new(Mutex::new(None));
130-
131-
// Back up previous hook, set new one
132-
let prev_hook = std::panic::take_hook();
133-
{
134-
let info = info.clone();
135-
std::panic::set_hook(Box::new(move |panic_info| {
136-
if let Some(location) = panic_info.location() {
137-
*info.lock().unwrap() = Some(GodotPanicInfo {
138-
file: location.file().to_string(),
139-
line: location.line(),
140-
//backtrace: Backtrace::capture(),
141-
});
142-
} else {
143-
println!("panic occurred but can't get location information...");
144-
}
145-
}));
146-
}
147-
148-
// Run code that should panic, restore hook
149-
let panic = std::panic::catch_unwind(code);
150-
std::panic::set_hook(prev_hook);
151-
152-
match panic {
153-
Ok(result) => Some(result),
154-
Err(err) => {
155-
// Flush, to make sure previous Rust output (e.g. test announcement, or debug prints during app) have been printed
156-
// TODO write custom panic handler and move this there, before panic backtrace printing
157-
flush_stdout();
158-
159-
let guard = info.lock().unwrap();
160-
let info = guard.as_ref().expect("no panic info available");
161-
log::godot_error!(
162-
"Rust function panicked in file {} at line {}. Context: {}",
163-
info.file,
164-
info.line,
165-
error_context()
166-
);
167-
//eprintln!("Backtrace:\n{}", info.backtrace);
168-
print_panic(err);
169-
None
170-
}
171-
}
172-
}
173-
174-
pub fn flush_stdout() {
175-
use std::io::Write;
176-
std::io::stdout().flush().expect("flush stdout");
177-
}
178-
179-
/// Ensure `T` is an editor plugin.
180-
pub const fn is_editor_plugin<T: crate::obj::Inherits<crate::engine::EditorPlugin>>() {}
181-
182-
// ------------------------------------------------------------------------------------------------------------------------------------------
183-
// Compatibility
184-
185-
// Code generated by Rust derive macros cannot cause any deprecation warnings, due to questionable "feature"
186-
// https://github.com/rust-lang/rust/pull/58994. Fortunately, an extra layer of indirection solves most problems: we generate a declarative
187-
// macro that itself isn't deprecated, but _its_ expansion is. Since the expansion happens in a later step, the warning is emitted.
188-
189-
#[inline(always)]
190-
#[deprecated = "#[base] is no longer needed; Base<T> is recognized directly. \n\
191-
More information on https://github.com/godot-rust/gdext/pull/577."]
192-
pub const fn base_attribute() {}
193-
194-
#[doc(hidden)]
195-
#[macro_export]
196-
macro_rules! __emit_deprecated_warning {
197-
($warning_fn:ident) => {
198-
const _: () = $crate::private::$warning_fn();
199-
};
200-
}
201-
202-
pub use crate::__emit_deprecated_warning;
203-
}
20453

20554
macro_rules! generate_gdextension_api_version {
20655
(

godot-core/src/private.rs

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* Copyright (c) godot-rust; Bromeon and contributors.
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
6+
*/
7+
8+
use std::sync::{Arc, Mutex};
9+
10+
pub use crate::gen::classes::class_macros;
11+
pub use crate::registry::{callbacks, ClassPlugin, ErasedRegisterFn, PluginItem};
12+
pub use crate::storage::{as_storage, Storage};
13+
pub use sys::out;
14+
15+
use crate::{log, sys};
16+
17+
// If someone forgets #[godot_api], this causes a compile error, rather than virtual functions not being called at runtime.
18+
#[allow(non_camel_case_types)]
19+
pub trait You_forgot_the_attribute__godot_api {}
20+
21+
sys::plugin_registry!(pub __GODOT_PLUGIN_REGISTRY: ClassPlugin);
22+
23+
pub(crate) fn iterate_plugins(mut visitor: impl FnMut(&ClassPlugin)) {
24+
sys::plugin_foreach!(__GODOT_PLUGIN_REGISTRY; visitor);
25+
}
26+
27+
pub use crate::obj::rtti::ObjectRtti;
28+
29+
pub struct ClassConfig {
30+
pub is_tool: bool,
31+
}
32+
33+
pub fn is_class_inactive(is_tool: bool) -> bool {
34+
if is_tool {
35+
return false;
36+
}
37+
38+
// SAFETY: only invoked after global library initialization.
39+
let global_config = unsafe { sys::config() };
40+
let is_editor = || crate::engine::Engine::singleton().is_editor_hint();
41+
42+
global_config.tool_only_in_editor //.
43+
&& global_config.is_editor_or_init(is_editor)
44+
}
45+
46+
pub fn print_panic(err: Box<dyn std::any::Any + Send>) {
47+
if let Some(s) = err.downcast_ref::<&'static str>() {
48+
print_panic_message(s);
49+
} else if let Some(s) = err.downcast_ref::<String>() {
50+
print_panic_message(s.as_str());
51+
} else {
52+
log::godot_error!("Rust panic of type ID {:?}", err.type_id());
53+
}
54+
}
55+
56+
pub fn auto_init<T>(l: &mut crate::obj::OnReady<T>) {
57+
l.init_auto();
58+
}
59+
60+
fn print_panic_message(msg: &str) {
61+
// If the message contains newlines, print all of the lines after a line break, and indent them.
62+
let lbegin = "\n ";
63+
let indented = msg.replace('\n', lbegin);
64+
65+
if indented.len() != msg.len() {
66+
log::godot_error!("Panic msg:{lbegin}{indented}");
67+
} else {
68+
log::godot_error!("Panic msg: {msg}");
69+
}
70+
}
71+
72+
struct GodotPanicInfo {
73+
line: u32,
74+
file: String,
75+
//backtrace: Backtrace, // for future use
76+
}
77+
78+
/// Executes `code`. If a panic is thrown, it is caught and an error message is printed to Godot.
79+
///
80+
/// Returns `None` if a panic occurred, and `Some(result)` with the result of `code` otherwise.
81+
#[must_use]
82+
pub fn handle_panic<E, F, R, S>(error_context: E, code: F) -> Option<R>
83+
where
84+
E: FnOnce() -> S,
85+
F: FnOnce() -> R + std::panic::UnwindSafe,
86+
S: std::fmt::Display,
87+
{
88+
let info: Arc<Mutex<Option<GodotPanicInfo>>> = Arc::new(Mutex::new(None));
89+
90+
// Back up previous hook, set new one
91+
let prev_hook = std::panic::take_hook();
92+
{
93+
let info = info.clone();
94+
std::panic::set_hook(Box::new(move |panic_info| {
95+
if let Some(location) = panic_info.location() {
96+
*info.lock().unwrap() = Some(GodotPanicInfo {
97+
file: location.file().to_string(),
98+
line: location.line(),
99+
//backtrace: Backtrace::capture(),
100+
});
101+
} else {
102+
println!("panic occurred but can't get location information...");
103+
}
104+
}));
105+
}
106+
107+
// Run code that should panic, restore hook
108+
let panic = std::panic::catch_unwind(code);
109+
std::panic::set_hook(prev_hook);
110+
111+
match panic {
112+
Ok(result) => Some(result),
113+
Err(err) => {
114+
// Flush, to make sure previous Rust output (e.g. test announcement, or debug prints during app) have been printed
115+
// TODO write custom panic handler and move this there, before panic backtrace printing
116+
flush_stdout();
117+
118+
let guard = info.lock().unwrap();
119+
let info = guard.as_ref().expect("no panic info available");
120+
log::godot_error!(
121+
"Rust function panicked in file {} at line {}. Context: {}",
122+
info.file,
123+
info.line,
124+
error_context()
125+
);
126+
//eprintln!("Backtrace:\n{}", info.backtrace);
127+
print_panic(err);
128+
None
129+
}
130+
}
131+
}
132+
133+
pub fn flush_stdout() {
134+
use std::io::Write;
135+
std::io::stdout().flush().expect("flush stdout");
136+
}
137+
138+
/// Ensure `T` is an editor plugin.
139+
pub const fn is_editor_plugin<T: crate::obj::Inherits<crate::engine::EditorPlugin>>() {}

0 commit comments

Comments
 (0)