|
1 | 1 | use std::ffi::CString;
|
2 | 2 |
|
| 3 | +use crate::core_types::GodotString; |
3 | 4 | use crate::sys;
|
4 | 5 |
|
| 6 | +// ---------------------------------------------------------------------------------------------------------------------------------------------- |
| 7 | +// Unsafe helpers for sys |
| 8 | + |
5 | 9 | static mut GODOT_API: Option<sys::GodotApi> = None;
|
6 | 10 | static mut GDNATIVE_LIBRARY_SYS: Option<*mut sys::godot_object> = None;
|
7 | 11 |
|
@@ -229,3 +233,98 @@ make_method_table!(struct NativeScriptMethodTable for NativeScript {
|
229 | 233 | set_library,
|
230 | 234 | new,
|
231 | 235 | });
|
| 236 | + |
| 237 | +// ---------------------------------------------------------------------------------------------------------------------------------------------- |
| 238 | +// Helper structs for init/terminate |
| 239 | + |
| 240 | +pub struct TerminateInfo { |
| 241 | + in_editor: bool, |
| 242 | +} |
| 243 | + |
| 244 | +impl TerminateInfo { |
| 245 | + #[inline] |
| 246 | + #[doc(hidden)] // avoids clippy warning: unsafe function's docs miss `# Safety` section |
| 247 | + pub unsafe fn new(options: *mut crate::sys::godot_gdnative_terminate_options) -> Self { |
| 248 | + assert!(!options.is_null(), "options were NULL"); |
| 249 | + |
| 250 | + let crate::sys::godot_gdnative_terminate_options { in_editor } = *options; |
| 251 | + |
| 252 | + Self { in_editor } |
| 253 | + } |
| 254 | + |
| 255 | + /// Returns `true` if the library is loaded in the Godot Editor. |
| 256 | + #[inline] |
| 257 | + pub fn in_editor(&self) -> bool { |
| 258 | + self.in_editor |
| 259 | + } |
| 260 | +} |
| 261 | + |
| 262 | +pub struct InitializeInfo { |
| 263 | + in_editor: bool, |
| 264 | + active_library_path: GodotString, |
| 265 | + options: *mut crate::sys::godot_gdnative_init_options, |
| 266 | +} |
| 267 | + |
| 268 | +impl InitializeInfo { |
| 269 | + /// Returns true if the library is loaded in the Godot Editor. |
| 270 | + #[inline] |
| 271 | + pub fn in_editor(&self) -> bool { |
| 272 | + self.in_editor |
| 273 | + } |
| 274 | + |
| 275 | + /// Returns a path to the library relative to the project. |
| 276 | + /// |
| 277 | + /// Example: `res://../../target/debug/libhello_world.dylib` |
| 278 | + #[inline] |
| 279 | + pub fn active_library_path(&self) -> &GodotString { |
| 280 | + &self.active_library_path |
| 281 | + } |
| 282 | + |
| 283 | + /// # Safety |
| 284 | + /// |
| 285 | + /// Will `panic!()` if options is NULL or invalid. |
| 286 | + #[inline] |
| 287 | + #[doc(hidden)] |
| 288 | + pub unsafe fn new(options: *mut crate::sys::godot_gdnative_init_options) -> Self { |
| 289 | + assert!(!options.is_null(), "options were NULL"); |
| 290 | + let crate::sys::godot_gdnative_init_options { |
| 291 | + in_editor, |
| 292 | + active_library_path, |
| 293 | + .. |
| 294 | + } = *options; |
| 295 | + |
| 296 | + let active_library_path = |
| 297 | + crate::core_types::GodotString::clone_from_sys(*active_library_path); |
| 298 | + |
| 299 | + Self { |
| 300 | + in_editor, |
| 301 | + active_library_path, |
| 302 | + options, |
| 303 | + } |
| 304 | + } |
| 305 | + |
| 306 | + #[inline] |
| 307 | + pub fn report_loading_error<T>(&self, message: T) |
| 308 | + where |
| 309 | + T: std::fmt::Display, |
| 310 | + { |
| 311 | + let crate::sys::godot_gdnative_init_options { |
| 312 | + report_loading_error, |
| 313 | + gd_native_library, |
| 314 | + .. |
| 315 | + } = unsafe { *self.options }; |
| 316 | + |
| 317 | + if let Some(report_loading_error_fn) = report_loading_error { |
| 318 | + // Add the trailing zero and convert Display => String |
| 319 | + let message = format!("{}\0", message); |
| 320 | + |
| 321 | + // Convert to FFI compatible string |
| 322 | + let message = std::ffi::CStr::from_bytes_with_nul(message.as_bytes()) |
| 323 | + .expect("message should not have a NULL"); |
| 324 | + |
| 325 | + unsafe { |
| 326 | + report_loading_error_fn(gd_native_library, message.as_ptr()); |
| 327 | + } |
| 328 | + } |
| 329 | + } |
| 330 | +} |
0 commit comments