use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
#[cfg(feature = "experimental-threads")] #[cfg_attr(published_docs, doc(cfg(feature = "experimental-threads")))]
use godot_cell::blocking::{InaccessibleGuard, MutGuard, RefGuard};
#[cfg(not(feature = "experimental-threads"))] #[cfg_attr(published_docs, doc(cfg(not(feature = "experimental-threads"))))]
use godot_cell::panicking::{InaccessibleGuard, MutGuard, RefGuard};
use godot_ffi::out;
use crate::obj::script::ScriptInstance;
use crate::obj::{AsDyn, Gd, GodotClass, PassiveGd};
#[derive(Debug)]
pub struct GdRef<'a, T: GodotClass> {
guard: RefGuard<'a, T>,
}
impl<'a, T: GodotClass> GdRef<'a, T> {
pub(crate) fn from_guard(guard: RefGuard<'a, T>) -> Self {
Self { guard }
}
}
impl<T: GodotClass> Deref for GdRef<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&self.guard
}
}
impl<T: GodotClass> Drop for GdRef<'_, T> {
fn drop(&mut self) {
out!("GdRef drop: {:?}", std::any::type_name::<T>());
}
}
#[derive(Debug)]
pub struct GdMut<'a, T: GodotClass> {
guard: MutGuard<'a, T>,
}
impl<'a, T: GodotClass> GdMut<'a, T> {
pub(crate) fn from_guard(guard: MutGuard<'a, T>) -> Self {
Self { guard }
}
}
impl<T: GodotClass> Deref for GdMut<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&self.guard
}
}
impl<T: GodotClass> DerefMut for GdMut<'_, T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.guard
}
}
impl<T: GodotClass> Drop for GdMut<'_, T> {
fn drop(&mut self) {
out!("GdMut drop: {:?}", std::any::type_name::<T>());
}
}
trait ErasedGuard<'a>: 'a {}
impl<'a, T: GodotClass> ErasedGuard<'a> for GdRef<'a, T> {}
impl<'a, T: GodotClass> ErasedGuard<'a> for GdMut<'a, T> {}
pub struct DynGdRef<'a, D: ?Sized> {
_guard: Box<dyn ErasedGuard<'a>>,
cached_ptr: *const D,
}
impl<'a, D> DynGdRef<'a, D>
where
D: ?Sized + 'static,
{
#[doc(hidden)]
pub fn from_guard<T: AsDyn<D>>(guard: GdRef<'a, T>) -> Self {
let obj = &*guard;
let dyn_obj = obj.dyn_upcast();
let cached_ptr = std::ptr::addr_of!(*dyn_obj);
Self {
_guard: Box::new(guard),
cached_ptr,
}
}
}
impl<D: ?Sized> Deref for DynGdRef<'_, D> {
type Target = D;
fn deref(&self) -> &D {
unsafe { &*self.cached_ptr }
}
}
impl<D: ?Sized> Drop for DynGdRef<'_, D> {
fn drop(&mut self) {
out!("DynGdRef drop: {:?}", std::any::type_name::<D>());
}
}
pub struct DynGdMut<'a, D: ?Sized> {
_guard: Box<dyn ErasedGuard<'a>>,
cached_ptr: *mut D,
}
impl<'a, D> DynGdMut<'a, D>
where
D: ?Sized + 'static,
{
#[doc(hidden)]
pub fn from_guard<T: AsDyn<D>>(mut guard: GdMut<'a, T>) -> Self {
let obj = &mut *guard;
let dyn_obj = obj.dyn_upcast_mut();
let cached_ptr = std::ptr::addr_of_mut!(*dyn_obj);
Self {
_guard: Box::new(guard),
cached_ptr,
}
}
}
impl<D: ?Sized> Deref for DynGdMut<'_, D> {
type Target = D;
fn deref(&self) -> &D {
unsafe { &*self.cached_ptr }
}
}
impl<D: ?Sized> DerefMut for DynGdMut<'_, D> {
fn deref_mut(&mut self) -> &mut D {
unsafe { &mut *self.cached_ptr }
}
}
impl<D: ?Sized> Drop for DynGdMut<'_, D> {
fn drop(&mut self) {
out!("DynGdMut drop: {:?}", std::any::type_name::<D>());
}
}
macro_rules! make_base_ref {
($ident:ident, $bound:ident, $doc_type:ident, $doc_path:path, $object_name:literal) => {
#[doc = concat!("This can be used to call methods on the base object of a ", $object_name, " that takes `&self` as the receiver.\n\n")]
#[doc = concat!("See [`", stringify!($doc_type), "::base()`](", stringify!($doc_path), "::base()) for usage.")]
pub struct $ident<'a, T: $bound> {
passive_gd: PassiveGd<T::Base>,
_instance: &'a T,
}
impl<'a, T: $bound> $ident<'a, T> {
pub(crate) fn new(passive_gd: PassiveGd<T::Base>, instance: &'a T) -> Self {
Self {
passive_gd,
_instance: instance,
}
}
}
impl<T: $bound> Deref for $ident<'_, T> {
type Target = Gd<T::Base>;
fn deref(&self) -> &Gd<T::Base> {
&self.passive_gd
}
}
};
}
macro_rules! make_base_mut {
($ident:ident, $bound:ident, $doc_type:ident, $doc_path:path, $object_name:literal) => {
#[doc = concat!("See [`", stringify!($doc_type), "::base_mut()`](", stringify!($doc_path), "::base_mut()) for usage.\n")]
pub struct $ident<'a, T: $bound> {
passive_gd: PassiveGd<T::Base>,
_inaccessible_guard: InaccessibleGuard<'a, T>,
}
impl<'a, T: $bound> $ident<'a, T> {
pub(crate) fn new(
passive_gd: PassiveGd<T::Base>,
inaccessible_guard: InaccessibleGuard<'a, T>,
) -> Self {
Self {
passive_gd,
_inaccessible_guard: inaccessible_guard,
}
}
}
impl<T: $bound> Deref for $ident<'_, T> {
type Target = Gd<T::Base>;
fn deref(&self) -> &Gd<T::Base> {
&self.passive_gd
}
}
impl<T: $bound> DerefMut for $ident<'_, T> {
fn deref_mut(&mut self) -> &mut Gd<T::Base> {
&mut self.passive_gd
}
}
};
}
make_base_ref!(
BaseRef,
GodotClass,
WithBaseField,
super::WithBaseField,
"Rust object"
);
make_base_mut!(
BaseMut,
GodotClass,
WithBaseField,
super::WithBaseField,
"Rust object"
);
make_base_ref!(
ScriptBaseRef,
ScriptInstance,
SiMut,
crate::obj::script::SiMut,
"[`ScriptInstance`]"
);
make_base_mut!(
ScriptBaseMut,
ScriptInstance,
SiMut,
crate::obj::script::SiMut,
"[`ScriptInstance`]"
);