use godot_ffi as sys;
use crate::builder::ClassBuilder;
use crate::builtin::GString;
use crate::init::InitLevel;
use crate::meta::ClassId;
use crate::meta::inspect::EnumConstant;
use crate::obj::signal::SignalObject;
use crate::obj::{Base, BaseMut, BaseRef, Bounds, Gd, bounds};
use crate::storage::Storage;
#[diagnostic::on_unimplemented(
message = "only classes registered with Godot are allowed in this context",
note = "you can use `#[derive(GodotClass)]` to register your own structs with Godot",
note = "see also: https://godot-rust.github.io/book/register/classes.html"
)]
pub trait GodotClass: Bounds + 'static
where
Self: Sized,
{
type Base: GodotClass;
fn class_id() -> ClassId;
const INIT_LEVEL: InitLevel = <Self::Base as GodotClass>::INIT_LEVEL;
fn inherits<Base: GodotClass>() -> bool {
if Self::class_id() == Base::class_id() {
true
} else if Self::Base::class_id() == <NoBase>::class_id() {
false
} else {
Self::Base::inherits::<Base>()
}
}
}
pub enum NoBase {}
impl GodotClass for NoBase {
type Base = NoBase;
fn class_id() -> ClassId {
ClassId::none()
}
const INIT_LEVEL: InitLevel = InitLevel::Core; }
unsafe impl Bounds for NoBase {
type Memory = bounds::MemManual;
type DynMemory = bounds::MemManual;
type Declarer = bounds::DeclEngine;
type Exportable = bounds::No;
}
pub unsafe trait Inherits<Base: GodotClass>: GodotClass {
const IS_SAME_CLASS: bool = false;
}
unsafe impl<T: GodotClass> Inherits<T> for T {
const IS_SAME_CLASS: bool = true;
}
#[diagnostic::on_unimplemented(
message = "`{Trait}` needs to be a trait object linked with class `{Self}` in the library",
note = "you can use `#[godot_dyn]` on `impl Trait for Class` to auto-generate `impl Implements<dyn Trait> for Class`"
)]
pub trait AsDyn<Trait>: GodotClass
where
Trait: ?Sized + 'static,
{
fn dyn_upcast(&self) -> &Trait;
fn dyn_upcast_mut(&mut self) -> &mut Trait;
}
#[doc(hidden)]
pub trait UserClass: Bounds<Declarer = bounds::DeclUser> {
#[doc(hidden)]
fn __config() -> crate::private::ClassConfig;
#[doc(hidden)]
fn __before_ready(&mut self);
#[doc(hidden)]
fn __default_virtual_call(
_method_name: &str,
#[cfg(since_api = "4.4")] _hash: u32,
) -> sys::GDExtensionClassCallVirtual {
None
}
}
pub trait EngineEnum: Copy + 'static {
fn try_from_ord(ord: i32) -> Option<Self>;
fn ord(self) -> i32;
fn from_ord(ord: i32) -> Self {
Self::try_from_ord(ord)
.unwrap_or_else(|| panic!("ordinal {ord} does not map to any enumerator"))
}
fn as_str(&self) -> &'static str;
fn values() -> &'static [Self];
fn all_constants() -> &'static [EnumConstant<Self>];
}
pub trait EngineBitfield: Copy + 'static {
fn try_from_ord(ord: u64) -> Option<Self>;
fn ord(self) -> u64;
fn from_ord(ord: u64) -> Self {
Self::try_from_ord(ord)
.unwrap_or_else(|| panic!("ordinal {ord} does not map to any valid bit flag"))
}
fn is_set(self, flag: Self) -> bool {
self.ord() & flag.ord() != 0
}
fn all_constants() -> &'static [EnumConstant<Self>];
}
pub trait IndexEnum: EngineEnum {
const ENUMERATOR_COUNT: usize;
fn to_index(self) -> usize {
self.ord() as usize
}
}
#[diagnostic::on_unimplemented(
message = "Class `{Self}` requires a `Base<T>` field",
label = "missing field `_base: Base<...>` in struct declaration",
note = "a base field is required to access the base from within `self`, as well as for #[signal], #[rpc] and #[func(virtual)]",
note = "see also: https://godot-rust.github.io/book/register/classes.html#the-base-field"
)]
pub trait WithBaseField: GodotClass + Bounds<Declarer = bounds::DeclUser> {
fn to_gd(&self) -> Gd<Self>;
#[doc(hidden)]
fn base_field(&self) -> &Base<Self::Base>;
fn base(&self) -> BaseRef<'_, Self> {
let passive_gd = unsafe { self.base_field().constructed_passive() };
BaseRef::new(passive_gd, self)
}
#[allow(clippy::let_unit_value)]
fn base_mut(&mut self) -> BaseMut<'_, Self> {
let passive_gd = unsafe { self.base_field().constructed_passive() };
let gd = self.to_gd();
let storage = unsafe {
gd.raw
.storage_unbounded()
.expect("we have Gd<Self>; its RawGd should not be null")
};
let guard = storage.get_inaccessible(self);
BaseMut::new(passive_gd, guard)
}
fn run_deferred<F>(&mut self, mut_self_method: F)
where
F: FnOnce(&mut Self) + 'static,
{
self.to_gd().run_deferred(mut_self_method)
}
fn run_deferred_gd<F>(&mut self, gd_function: F)
where
F: FnOnce(Gd<Self>) + 'static,
{
self.to_gd().run_deferred_gd(gd_function)
}
}
pub trait WithSignals: Inherits<crate::classes::Object> {
type SignalCollection<'c, C>
where
C: WithSignals;
#[doc(hidden)]
type __SignalObj<'c>: SignalObject<'c>;
#[doc(hidden)]
fn __signals_from_external(external: &Gd<Self>) -> Self::SignalCollection<'_, Self>;
}
pub trait WithUserSignals: WithSignals + WithBaseField {
fn signals(&mut self) -> Self::SignalCollection<'_, Self>;
}
pub trait NewGd: GodotClass {
fn new_gd() -> Gd<Self>;
}
impl<T> NewGd for T
where
T: cap::GodotDefault + Bounds<Memory = bounds::MemRefCounted>,
{
fn new_gd() -> Gd<Self> {
Gd::default()
}
}
pub trait NewAlloc: GodotClass {
#[must_use]
fn new_alloc() -> Gd<Self>;
}
pub trait Singleton: GodotClass {
fn singleton() -> Gd<Self>;
}
pub trait UserSingleton:
GodotClass + Bounds<Declarer = bounds::DeclUser, Memory = bounds::MemManual>
{
}
impl<T> Singleton for T
where
T: UserSingleton + Inherits<crate::classes::Object>,
{
fn singleton() -> Gd<T> {
let class_name = <T as GodotClass>::class_id().to_string_name();
unsafe { crate::classes::singleton_unchecked(&class_name) }
}
}
impl<T> NewAlloc for T
where
T: cap::GodotDefault + Bounds<Memory = bounds::MemManual>,
{
fn new_alloc() -> Gd<Self> {
use crate::obj::bounds::Declarer as _;
<Self as Bounds>::Declarer::create_gd()
}
}
pub mod cap {
use std::any::Any;
use super::*;
use crate::builtin::{StringName, Variant};
use crate::obj::{Base, Gd};
use crate::registry::info::PropertyInfo;
use crate::storage::{IntoVirtualMethodReceiver, VirtualMethodReceiver};
#[diagnostic::on_unimplemented(
message = "Class `{Self}` requires either an `init` constructor, or explicit opt-out",
label = "needs `init`",
note = "to provide a default constructor, use `#[class(init)]` or implement an `init` method",
note = "to opt out, use `#[class(no_init)]`",
note = "see also: https://godot-rust.github.io/book/register/constructors.html"
)]
pub trait GodotDefault: GodotClass {
#[doc(hidden)]
fn __godot_default() -> Gd<Self> {
sys::strict_assert_eq!(
std::any::TypeId::of::<<Self as Bounds>::Declarer>(),
std::any::TypeId::of::<bounds::DeclUser>(),
"__godot_default() called on engine class; must be overridden for engine classes"
);
Gd::default_instance()
}
#[doc(hidden)]
fn __godot_user_init(_base: Base<Self::Base>) -> Self {
unreachable!(
"__godot_user_init() called on engine class; must be overridden for user classes"
)
}
}
#[doc(hidden)]
pub trait GodotToString: GodotClass {
#[doc(hidden)]
type Recv: IntoVirtualMethodReceiver<Self>;
#[doc(hidden)]
fn __godot_to_string(this: VirtualMethodReceiver<Self>) -> GString;
}
#[doc(hidden)]
pub trait GodotNotification: GodotClass {
#[doc(hidden)]
fn __godot_notification(&mut self, what: i32);
}
#[doc(hidden)]
pub trait GodotRegisterClass: GodotClass {
#[doc(hidden)]
fn __godot_register_class(builder: &mut ClassBuilder<Self>);
}
#[doc(hidden)]
pub trait GodotGet: GodotClass {
#[doc(hidden)]
type Recv: IntoVirtualMethodReceiver<Self>;
#[doc(hidden)]
fn __godot_get_property(
this: VirtualMethodReceiver<Self>,
property: StringName,
) -> Option<Variant>;
}
#[doc(hidden)]
pub trait GodotSet: GodotClass {
#[doc(hidden)]
type Recv: IntoVirtualMethodReceiver<Self>;
#[doc(hidden)]
fn __godot_set_property(
this: VirtualMethodReceiver<Self>,
property: StringName,
value: Variant,
) -> bool;
}
#[doc(hidden)]
pub trait GodotGetPropertyList: GodotClass {
#[doc(hidden)]
type Recv: IntoVirtualMethodReceiver<Self>;
#[doc(hidden)]
fn __godot_get_property_list(
this: VirtualMethodReceiver<Self>,
) -> Vec<crate::registry::info::PropertyInfo>;
}
#[doc(hidden)]
pub trait GodotPropertyGetRevert: GodotClass {
#[doc(hidden)]
type Recv: IntoVirtualMethodReceiver<Self>;
#[doc(hidden)]
fn __godot_property_get_revert(
this: VirtualMethodReceiver<Self>,
property: StringName,
) -> Option<Variant>;
}
#[doc(hidden)]
pub trait GodotValidateProperty: GodotClass {
#[doc(hidden)]
type Recv: IntoVirtualMethodReceiver<Self>;
#[doc(hidden)]
fn __godot_validate_property(
this: VirtualMethodReceiver<Self>,
property: &mut PropertyInfo,
);
}
pub trait ImplementsGodotApi: GodotClass {
#[doc(hidden)]
fn __register_methods();
#[doc(hidden)]
fn __register_constants();
#[doc(hidden)]
fn __register_rpcs(_: &mut dyn Any) {}
}
pub trait ImplementsGodotExports: GodotClass {
#[doc(hidden)]
fn __register_exports();
}
pub trait ImplementsGodotVirtual: GodotClass {
#[cfg(before_api = "4.4")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.4")))]
#[doc(hidden)]
fn __virtual_call(name: &str) -> sys::GDExtensionClassCallVirtual;
#[cfg(since_api = "4.4")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.4")))]
#[doc(hidden)]
fn __virtual_call(name: &str, hash: u32) -> sys::GDExtensionClassCallVirtual;
}
}