use std::cell::Cell;
use super::GodotBinding;
use crate::ManualInitCell;
pub(super) struct BindingStorage {
initialized: Cell<bool>,
binding: ManualInitCell<GodotBinding>,
}
impl BindingStorage {
#[inline(always)]
unsafe fn storage() -> &'static Self {
static BINDING: BindingStorage = BindingStorage {
initialized: Cell::new(false),
binding: ManualInitCell::new(),
};
&BINDING
}
fn initialized(&self) -> bool {
self.initialized.get()
}
unsafe fn set_initialized(&self, initialized: bool) {
if initialized == self.initialized() {
if initialized {
panic!("already initialized");
} else {
panic!("deinitialize without prior initialize");
}
}
self.initialized.set(initialized);
}
pub unsafe fn initialize(binding: GodotBinding) {
let storage = unsafe { Self::storage() };
unsafe { storage.set_initialized(true) };
unsafe { storage.binding.set(binding) };
}
pub unsafe fn deinitialize() {
let storage = unsafe { Self::storage() };
unsafe { storage.set_initialized(false) };
unsafe { storage.binding.clear() };
}
#[inline(always)]
pub unsafe fn get_binding_unchecked() -> &'static GodotBinding {
let storage = unsafe { Self::storage() };
Self::ensure_main_thread();
unsafe { storage.binding.get_unchecked() }
}
pub fn is_initialized() -> bool {
let storage = unsafe { Self::storage() };
storage.initialized()
}
fn ensure_main_thread() {
#[cfg(all(safeguards_balanced, not(wasm_nothreads)))] #[cfg_attr(published_docs, doc(cfg(all(safeguards_balanced, not(wasm_nothreads)))))]
if !crate::is_main_thread() {
if std::thread::panicking() {
eprintln!(
"ERROR: Attempted to access binding from different thread than main thread; this is UB.\n\
Cannot panic because panic unwind is already in progress. Please check surrounding messages to fix the bug."
);
} else {
panic!(
"attempted to access binding from different thread than main thread; \
this is UB - use the \"experimental-threads\" feature."
)
};
}
}
}
unsafe impl Sync for BindingStorage {}
unsafe impl Send for BindingStorage {}
pub struct GdextConfig {
pub tool_only_in_editor: bool,
is_editor: std::cell::OnceCell<bool>,
}
impl GdextConfig {
pub fn new(tool_only_in_editor: bool) -> Self {
Self {
tool_only_in_editor,
is_editor: std::cell::OnceCell::new(),
}
}
pub fn is_editor_or_init(&self, is_editor: impl FnOnce() -> bool) -> bool {
*self.is_editor.get_or_init(is_editor)
}
}