use crate::{
BuiltinLifecycleTable, BuiltinMethodTable, ClassCoreMethodTable, ClassEditorMethodTable,
ClassSceneMethodTable, ClassServersMethodTable, GDExtensionClassLibraryPtr,
GDExtensionInterface, GdextRuntimeMetadata, ManualInitCell, UtilityFunctionTable,
};
#[cfg(feature = "experimental-threads")] #[cfg_attr(published_docs, doc(cfg(feature = "experimental-threads")))]
mod multi_threaded;
#[cfg(not(feature = "experimental-threads"))] #[cfg_attr(published_docs, doc(cfg(not(feature = "experimental-threads"))))]
mod single_threaded;
#[cfg(feature = "experimental-threads")] #[cfg_attr(published_docs, doc(cfg(feature = "experimental-threads")))]
use multi_threaded::BindingStorage;
#[cfg(feature = "experimental-threads")] #[cfg_attr(published_docs, doc(cfg(feature = "experimental-threads")))]
pub use multi_threaded::GdextConfig;
#[cfg(not(feature = "experimental-threads"))] #[cfg_attr(published_docs, doc(cfg(not(feature = "experimental-threads"))))]
use single_threaded::BindingStorage;
#[cfg(not(feature = "experimental-threads"))] #[cfg_attr(published_docs, doc(cfg(not(feature = "experimental-threads"))))]
pub use single_threaded::GdextConfig;
pub(crate) struct GodotBinding {
interface: GDExtensionInterface,
get_proc_address: crate::GDExtensionInterfaceGetProcAddress,
library: ClassLibraryPtr,
global_method_table: BuiltinLifecycleTable,
class_core_method_table: ManualInitCell<ClassCoreMethodTable>,
class_server_method_table: ManualInitCell<ClassServersMethodTable>,
class_scene_method_table: ManualInitCell<ClassSceneMethodTable>,
class_editor_method_table: ManualInitCell<ClassEditorMethodTable>,
builtin_method_table: ManualInitCell<BuiltinMethodTable>,
utility_function_table: UtilityFunctionTable,
runtime_metadata: GdextRuntimeMetadata,
config: GdextConfig,
}
impl GodotBinding {
pub fn new(
interface: GDExtensionInterface,
get_proc_address: crate::GDExtensionInterfaceGetProcAddress,
library: GDExtensionClassLibraryPtr,
global_method_table: BuiltinLifecycleTable,
utility_function_table: UtilityFunctionTable,
runtime_metadata: GdextRuntimeMetadata,
config: GdextConfig,
) -> Self {
Self {
interface,
get_proc_address,
library: ClassLibraryPtr(library),
global_method_table,
class_core_method_table: ManualInitCell::new(),
class_server_method_table: ManualInitCell::new(),
class_scene_method_table: ManualInitCell::new(),
class_editor_method_table: ManualInitCell::new(),
builtin_method_table: ManualInitCell::new(),
utility_function_table,
runtime_metadata,
config,
}
}
}
struct ClassLibraryPtr(crate::GDExtensionClassLibraryPtr);
unsafe impl Sync for ClassLibraryPtr {}
unsafe impl Send for ClassLibraryPtr {}
#[allow(unsafe_op_in_unsafe_fn)] unsafe fn initialize_table<T>(table: &ManualInitCell<T>, value: T, _what: &str) {
crate::strict_assert!(
!table.is_initialized(),
"method table for {_what} should only be initialized once"
);
table.set(value)
}
#[allow(unsafe_op_in_unsafe_fn)] unsafe fn get_table<T>(table: &'static ManualInitCell<T>, _msg: &str) -> &'static T {
crate::strict_assert!(table.is_initialized(), "{_msg}");
table.get_unchecked()
}
#[inline(always)]
#[allow(unsafe_op_in_unsafe_fn)] pub unsafe fn get_interface() -> &'static GDExtensionInterface {
&get_binding().interface
}
#[inline(always)]
#[allow(unsafe_op_in_unsafe_fn)] pub unsafe fn get_library() -> crate::GDExtensionClassLibraryPtr {
get_binding().library.0
}
#[inline]
#[allow(unsafe_op_in_unsafe_fn)] pub unsafe fn get_ffi_ptr_by_cstr(name: &[u8]) -> crate::GDExtensionInterfaceFunctionPtr {
let get_proc_address = get_binding()
.get_proc_address
.expect("get_proc_address should be available");
get_proc_address(crate::c_str(name))
}
#[inline(always)]
#[allow(unsafe_op_in_unsafe_fn)] pub unsafe fn builtin_lifecycle_api() -> &'static BuiltinLifecycleTable {
&get_binding().global_method_table
}
#[inline(always)]
#[allow(unsafe_op_in_unsafe_fn)] pub unsafe fn class_servers_api() -> &'static ClassServersMethodTable {
get_table(
&get_binding().class_server_method_table,
"cannot fetch classes; init level 'Servers' not yet loaded",
)
}
#[inline(always)]
#[allow(unsafe_op_in_unsafe_fn)] pub unsafe fn class_core_api() -> &'static ClassCoreMethodTable {
get_table(
&get_binding().class_core_method_table,
"cannot fetch classes; init level 'Core' not yet loaded",
)
}
#[inline(always)]
#[allow(unsafe_op_in_unsafe_fn)] pub unsafe fn class_scene_api() -> &'static ClassSceneMethodTable {
get_table(
&get_binding().class_scene_method_table,
"cannot fetch classes; init level 'Scene' not yet loaded",
)
}
#[inline(always)]
#[allow(unsafe_op_in_unsafe_fn)] pub unsafe fn class_editor_api() -> &'static ClassEditorMethodTable {
get_table(
&get_binding().class_editor_method_table,
"cannot fetch classes; init level 'Editor' not yet loaded",
)
}
#[inline(always)]
#[allow(unsafe_op_in_unsafe_fn)] pub unsafe fn builtin_method_table() -> &'static BuiltinMethodTable {
get_table(
&get_binding().builtin_method_table,
"cannot fetch builtin methods; table not ready",
)
}
#[inline(always)]
#[allow(unsafe_op_in_unsafe_fn)] pub unsafe fn utility_function_table() -> &'static UtilityFunctionTable {
&get_binding().utility_function_table
}
#[inline]
#[allow(unsafe_op_in_unsafe_fn)] pub unsafe fn config() -> &'static GdextConfig {
&get_binding().config
}
#[inline]
pub fn is_initialized() -> bool {
BindingStorage::is_initialized()
}
#[allow(unsafe_op_in_unsafe_fn)] pub(crate) unsafe fn initialize_binding(binding: GodotBinding) {
BindingStorage::initialize(binding);
}
#[allow(unsafe_op_in_unsafe_fn)] pub(crate) unsafe fn deinitialize_binding() {
BindingStorage::deinitialize();
}
#[inline(always)]
#[allow(unsafe_op_in_unsafe_fn)] pub(crate) unsafe fn get_binding() -> &'static GodotBinding {
BindingStorage::get_binding_unchecked()
}
#[allow(unsafe_op_in_unsafe_fn)] pub(crate) unsafe fn initialize_class_core_method_table(table: ClassCoreMethodTable) {
initialize_table(
&get_binding().class_core_method_table,
table,
"classes (Core level)",
)
}
#[allow(unsafe_op_in_unsafe_fn)] pub(crate) unsafe fn initialize_class_server_method_table(table: ClassServersMethodTable) {
initialize_table(
&get_binding().class_server_method_table,
table,
"classes (Server level)",
)
}
#[allow(unsafe_op_in_unsafe_fn)] pub(crate) unsafe fn initialize_class_scene_method_table(table: ClassSceneMethodTable) {
initialize_table(
&get_binding().class_scene_method_table,
table,
"classes (Scene level)",
)
}
#[inline(always)]
#[allow(unsafe_op_in_unsafe_fn)] pub(crate) unsafe fn runtime_metadata() -> &'static GdextRuntimeMetadata {
&get_binding().runtime_metadata
}
#[allow(unsafe_op_in_unsafe_fn)] pub(crate) unsafe fn initialize_class_editor_method_table(table: ClassEditorMethodTable) {
initialize_table(
&get_binding().class_editor_method_table,
table,
"classes (Editor level)",
)
}
#[allow(unsafe_op_in_unsafe_fn)] pub(crate) unsafe fn initialize_builtin_method_table(table: BuiltinMethodTable) {
initialize_table(&get_binding().builtin_method_table, table, "builtins")
}