Skip to content

Commit f92d12f

Browse files
author
toasteater
authored
Merge pull request #309 from stewbasic/master
Report initialization errors to Godot.
2 parents ceb3f0e + 6cffda6 commit f92d12f

File tree

4 files changed

+132
-36
lines changed

4 files changed

+132
-36
lines changed

gdnative-core/src/lib.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,34 @@ pub fn result_from_sys(err: sys::godot_error) -> GodotResult {
185185

186186
Err(unsafe { mem::transmute(err as u32) })
187187
}
188+
189+
pub unsafe fn report_init_error(
190+
options: *const sys::godot_gdnative_init_options,
191+
error: sys::InitError,
192+
) {
193+
use std::ffi::CString;
194+
match error {
195+
sys::InitError::VersionMismatch {
196+
api_type,
197+
want,
198+
got,
199+
} => {
200+
if let Some(f) = (*options).report_version_mismatch {
201+
f(
202+
(*options).gd_native_library,
203+
CString::new(format!("{}", api_type)).unwrap().as_ptr(),
204+
want,
205+
got,
206+
);
207+
}
208+
}
209+
sys::InitError::Generic { message } => {
210+
if let Some(f) = (*options).report_loading_error {
211+
f(
212+
(*options).gd_native_library,
213+
CString::new(message).unwrap().as_ptr(),
214+
);
215+
}
216+
}
217+
}
218+
}

gdnative-core/src/macros.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,14 @@ macro_rules! godot_gdnative_init {
3131
#[doc(hidden)]
3232
pub extern "C" fn $fn_name(options: *mut $crate::sys::godot_gdnative_init_options) {
3333
unsafe {
34-
$crate::GODOT_API = Some($crate::GodotApi::from_raw((*options).api_struct));
34+
let api = match $crate::GodotApi::from_raw((*options).api_struct) {
35+
Ok(api) => api,
36+
Err(e) => {
37+
$crate::report_init_error(options, e);
38+
return;
39+
}
40+
};
41+
$crate::GODOT_API = Some(api);
3542
$crate::GDNATIVE_LIBRARY_SYS = Some((*options).gd_native_library);
3643
}
3744
let api = $crate::get_api();
@@ -81,6 +88,9 @@ macro_rules! godot_gdnative_terminate {
8188
#[no_mangle]
8289
#[doc(hidden)]
8390
pub extern "C" fn $fn_name(options: *mut $crate::sys::godot_gdnative_terminate_options) {
91+
if unsafe { $crate::GODOT_API.is_none() } {
92+
return;
93+
}
8494
$callback(options);
8595

8696
unsafe {
@@ -120,6 +130,9 @@ macro_rules! godot_nativescript_init {
120130
#[no_mangle]
121131
#[doc(hidden)]
122132
pub extern "C" fn $fn_name(handle: *mut $crate::libc::c_void) {
133+
if unsafe { $crate::GODOT_API.is_none() } {
134+
return;
135+
}
123136
unsafe {
124137
$callback($crate::init::InitHandle::new(handle));
125138
}

gdnative-sys/build.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -337,26 +337,26 @@ mod api_wrapper {
337337
let v_min = api.version.minor;
338338
let gd_api_struct = api.godot_api_struct();
339339
godot_apis.extend(quote! {
340-
let #i = find_api_ptr(core_api_struct, #gd_api_type, #v_maj, #v_min) as *const #gd_api_struct;
340+
let #i = find_api_ptr(core_api_struct, #gd_api_type, #v_maj, #v_min)? as *const #gd_api_struct;
341341
});
342342
for function in &api.functions {
343343
let function_name = function.rust_name();
344-
let expect_msg = format!(
344+
let message = format!(
345345
"API function missing: {}.{}",
346346
api.godot_api_struct(),
347347
function_name
348348
);
349349
constructed_struct_fields.extend(quote! {
350-
#function_name: (*#i).#function_name.expect(#expect_msg),
350+
#function_name: map_option_to_init_error((*#i).#function_name, #message)?,
351351
});
352352
}
353353
}
354354
quote! {
355-
pub unsafe fn from_raw(core_api_struct: *const godot_gdnative_core_api_struct) -> Self {
355+
pub unsafe fn from_raw(core_api_struct: *const godot_gdnative_core_api_struct) -> Result<Self, InitError> {
356356
#godot_apis
357-
GodotApi{
357+
Ok(GodotApi{
358358
#constructed_struct_fields
359-
}
359+
})
360360
}
361361
}
362362
}

gdnative-sys/src/lib.rs

Lines changed: 81 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,46 +7,98 @@
77
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
88
include!(concat!(env!("OUT_DIR"), "/api_wrapper.rs"));
99

10-
unsafe fn find_api_ptr(
11-
core_api: *const godot_gdnative_core_api_struct,
10+
pub enum InitError {
11+
VersionMismatch {
12+
api_type: GDNATIVE_API_TYPES,
13+
want: godot_gdnative_api_version,
14+
got: godot_gdnative_api_version,
15+
},
16+
Generic {
17+
message: String,
18+
},
19+
}
20+
21+
fn map_option_to_init_error<T>(t: Option<T>, message: &'static str) -> Result<T, InitError> {
22+
match t {
23+
Some(t) => Ok(t),
24+
None => Err(InitError::Generic {
25+
message: message.to_string(),
26+
}),
27+
}
28+
}
29+
30+
unsafe fn find_version(
31+
mut api: *const godot_gdnative_api_struct,
1232
api_type: GDNATIVE_API_TYPES,
1333
version_major: u32,
1434
version_minor: u32,
15-
) -> *const godot_gdnative_api_struct {
16-
let mut api = core_api as *const godot_gdnative_api_struct;
35+
) -> Option<Result<*const godot_gdnative_api_struct, InitError>> {
36+
let mut got = None;
1737
if (*api).type_ as u32 == api_type as u32 {
1838
while !api.is_null() {
19-
if (*api).version.minor == version_minor
20-
&& (*api).version.major == version_major
21-
// The boolean expression below SHOULD always be true;
22-
// we will double check to be safe.
23-
&& (*api).type_ as u32 == api_type as u32
24-
{
25-
return api;
39+
// The boolean expression below SHOULD always be true;
40+
// we will double check to be safe.
41+
if (*api).type_ as u32 == api_type as u32 {
42+
let (major, minor) = ((*api).version.major, (*api).version.minor);
43+
if major == version_major && minor == version_minor {
44+
return Some(Ok(api));
45+
} else {
46+
got = Some(godot_gdnative_api_version { major, minor });
47+
}
2648
}
2749
api = (*api).next;
2850
}
2951
}
52+
got.map(|got| {
53+
Err(InitError::VersionMismatch {
54+
want: godot_gdnative_api_version {
55+
major: version_major,
56+
minor: version_minor,
57+
},
58+
got,
59+
api_type,
60+
})
61+
})
62+
}
63+
64+
unsafe fn find_api_ptr(
65+
core_api: *const godot_gdnative_core_api_struct,
66+
api_type: GDNATIVE_API_TYPES,
67+
version_major: u32,
68+
version_minor: u32,
69+
) -> Result<*const godot_gdnative_api_struct, InitError> {
70+
let mut last_error = None;
71+
match find_version(
72+
core_api as *const godot_gdnative_api_struct,
73+
api_type,
74+
version_major,
75+
version_minor,
76+
) {
77+
Some(Ok(api)) => {
78+
return Ok(api);
79+
}
80+
Some(Err(error)) => {
81+
last_error = Some(error);
82+
}
83+
None => {}
84+
}
3085
for i in 0..(*core_api).num_extensions {
31-
let mut extension =
32-
*(*core_api).extensions.offset(i as _) as *const godot_gdnative_api_struct;
33-
if (*extension).type_ as u32 == api_type as u32 {
34-
while !extension.is_null() {
35-
if (*extension).version.minor == version_minor
36-
&& (*extension).version.major == version_major
37-
// The boolean expression below SHOULD always be true;
38-
// we will double check to be safe.
39-
&& (*extension).type_ as u32 == api_type as u32
40-
{
41-
return extension;
42-
}
43-
extension = (*extension).next;
86+
match find_version(
87+
*(*core_api).extensions.offset(i as _),
88+
api_type,
89+
version_major,
90+
version_minor,
91+
) {
92+
Some(Ok(api)) => {
93+
return Ok(api);
94+
}
95+
Some(Err(error)) => {
96+
last_error = Some(error);
4497
}
98+
None => {}
4599
}
46100
}
47-
panic!(
48-
"Couldn't find API struct with type {type}, version {version:?}",
49-
type = api_type,
50-
version = (version_major, version_minor),
51-
);
101+
Err(last_error.unwrap_or(InitError::Generic {
102+
message: format!("Couldn't find API struct with type {}", api_type),
103+
}))
52104
}

0 commit comments

Comments
 (0)