use std::fmt::Display;
use std::marker::PhantomData;
use func_state::FuncState;
use gdnative_bindings::Object;
use gdnative_core::core_types::{GodotError, Variant};
use gdnative_core::init::InitHandle;
use gdnative_core::object::{Instance, SubClass, TInstance, TRef};
use crate::future;
mod bridge;
mod func_state;
pub struct Context {
func_state: Instance<FuncState>,
_marker: PhantomData<*const ()>,
}
impl Context {
pub(crate) fn new() -> Self {
Context {
func_state: FuncState::new().into_shared(),
_marker: PhantomData,
}
}
pub(crate) fn func_state(&self) -> Instance<FuncState> {
self.func_state.clone()
}
fn safe_func_state(&self) -> TInstance<'_, FuncState> {
unsafe { self.func_state.assume_safe() }
}
pub(crate) fn resolve(&self, value: Variant) {
func_state::resolve(self.safe_func_state(), value);
}
pub fn until_resume(&self) -> future::Yield<Variant> {
let (future, resume) = future::make();
func_state::make_resumable(self.safe_func_state(), resume);
future
}
pub fn signal<C>(
&self,
obj: TRef<'_, C>,
signal: &str,
) -> Result<future::Yield<Vec<Variant>>, GodotError>
where
C: SubClass<Object>,
{
let (future, resume) = future::make();
bridge::SignalBridge::connect(obj.upcast(), signal, resume)?;
Ok(future)
}
}
pub fn register_runtime(handle: &InitHandle) {
register_runtime_with_prefix(handle, "__GDNATIVE_ASYNC_INTERNAL__")
}
pub fn register_runtime_with_prefix<S>(handle: &InitHandle, prefix: S)
where
S: Display,
{
handle.add_class_as::<bridge::SignalBridge>(format!("{prefix}SignalBridge"));
handle.add_class_as::<func_state::FuncState>(format!("{prefix}FuncState"));
}
pub fn terminate_runtime() {
bridge::terminate();
}