use std::borrow::Borrow;
use std::ffi::CString;
use std::fmt::{self, Debug};
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::Deref;
use std::ptr::NonNull;
use bounds::{
AssumeSafeLifetime, LifetimeConstraint, MemorySpec, PtrWrapper, RefImplBound, SafeAsRaw,
SafeDeref,
};
use memory::{ManuallyManaged, Memory, RefCounted};
use ownership::{NonUniqueOwnership, Ownership, Shared, ThreadLocal, Unique};
use crate::export::NativeClass;
use crate::private::{get_api, ManuallyManagedClassPlaceholder, ReferenceCountedClassPlaceholder};
use crate::sys;
pub use as_arg::*;
pub use instance::*;
pub use new_ref::NewRef;
pub use raw::RawObject;
pub mod bounds;
pub mod memory;
pub mod ownership;
mod as_arg;
mod instance;
mod new_ref;
mod raw;
pub unsafe trait GodotObject: Sized + crate::private::godot_object::Sealed {
type Memory: Memory;
fn class_name() -> &'static str;
#[inline]
fn null() -> Null<Self> {
Null::null()
}
#[inline]
fn new() -> Ref<Self, Unique>
where
Self: Instanciable,
{
Ref::new()
}
#[inline]
fn cast<T>(&self) -> Option<&T>
where
T: GodotObject + SubClass<Self>,
{
self.as_raw().cast().map(T::cast_ref)
}
#[inline(always)]
fn upcast<T>(&self) -> &T
where
T: GodotObject,
Self: SubClass<T>,
{
unsafe { T::cast_ref(self.as_raw().cast_unchecked()) }
}
#[doc(hidden)]
#[inline]
fn cast_ref(raw: &RawObject<Self>) -> &Self {
unsafe { &*(raw as *const _ as *const _) }
}
#[doc(hidden)]
#[inline]
fn as_raw(&self) -> &RawObject<Self> {
unsafe { &*(self as *const _ as *const _) }
}
#[doc(hidden)]
#[inline]
fn as_ptr(&self) -> *mut sys::godot_object {
self.as_raw().sys().as_ptr()
}
#[inline]
unsafe fn assume_shared(&self) -> Ref<Self, Shared>
where
Self: Sized,
{
Ref::from_sys(self.as_raw().sys())
}
#[inline]
unsafe fn assume_thread_local(&self) -> Ref<Self, ThreadLocal>
where
Self: Sized + GodotObject<Memory = RefCounted>,
{
Ref::from_sys(self.as_raw().sys())
}
#[inline]
unsafe fn assume_unique(&self) -> Ref<Self, Unique>
where
Self: Sized,
{
Ref::from_sys(self.as_raw().sys())
}
#[inline]
unsafe fn try_from_instance_id<'a>(id: i64) -> Option<TRef<'a, Self, Shared>> {
TRef::try_from_instance_id(id)
}
#[inline]
unsafe fn from_instance_id<'a>(id: i64) -> TRef<'a, Self, Shared> {
TRef::from_instance_id(id)
}
}
pub unsafe trait SubClass<A: GodotObject>: GodotObject {}
unsafe impl<T: GodotObject> SubClass<T> for T {}
pub trait Instanciable: GodotObject {
fn construct() -> Ref<Self, Unique>;
}
pub trait QueueFree: GodotObject {
#[doc(hidden)]
unsafe fn godot_queue_free(sys: *mut sys::godot_object);
}
pub struct Ref<T: GodotObject, Own: Ownership = Shared> {
ptr: <T::Memory as MemorySpec>::PtrWrapper,
_marker: PhantomData<(*const T, Own)>,
}
unsafe impl<T: GodotObject, Own: Ownership + Send> Send for Ref<T, Own> {}
unsafe impl<T: GodotObject, Own: Ownership + Sync> Sync for Ref<T, Own> {}
impl<T, Own> Copy for Ref<T, Own>
where
T: GodotObject<Memory = ManuallyManaged>,
Own: NonUniqueOwnership,
{
}
impl<T, Own> Clone for Ref<T, Own>
where
T: GodotObject,
Own: NonUniqueOwnership,
{
#[inline]
fn clone(&self) -> Self {
unsafe { Ref::from_sys(self.ptr.as_non_null()) }
}
}
impl<T: GodotObject + Instanciable> Ref<T, Unique> {
#[inline]
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
T::construct()
}
}
impl<T: GodotObject> Ref<T, Unique> {
#[inline]
pub fn by_class_name(class_name: &str) -> Option<Self> {
unsafe {
let class_name = CString::new(class_name).ok()?;
let ctor = (get_api().godot_get_class_constructor)(class_name.as_ptr())?;
let ptr = NonNull::new(ctor() as *mut sys::godot_object)?;
<T::Memory as MemorySpec>::impl_from_maybe_ref_counted(ptr)
}
}
}
impl<T: GodotObject, Own: Ownership> Ref<T, Own>
where
RefImplBound: SafeDeref<T::Memory, Own>,
{
#[inline]
pub fn as_ref(&self) -> TRef<'_, T, Own> {
RefImplBound::impl_as_ref(self)
}
}
impl<T: GodotObject, Own: Ownership> Deref for Ref<T, Own>
where
RefImplBound: SafeDeref<T::Memory, Own>,
{
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
RefImplBound::impl_as_ref(self).obj
}
}
impl<T: GodotObject, Own: Ownership> Borrow<T> for Ref<T, Own>
where
RefImplBound: SafeDeref<T::Memory, Own>,
{
#[inline]
fn borrow(&self) -> &T {
RefImplBound::impl_as_ref(self).obj
}
}
impl<T: GodotObject, Own: Ownership> Ref<T, Own>
where
RefImplBound: SafeAsRaw<T::Memory, Own>,
{
#[inline]
#[doc(hidden)]
pub fn as_raw(&self) -> &RawObject<T> {
unsafe { self.as_raw_unchecked() }
}
#[inline]
pub fn cast<U>(self) -> Option<Ref<U, Own>>
where
U: GodotObject<Memory = T::Memory> + SubClass<T>,
{
self.try_cast().ok()
}
#[inline]
pub fn upcast<U>(self) -> Ref<U, Own>
where
U: GodotObject<Memory = T::Memory>,
T: SubClass<U>,
{
unsafe { self.cast_unchecked() }
}
#[inline]
pub fn try_cast<U>(self) -> Result<Ref<U, Own>, Self>
where
U: GodotObject<Memory = T::Memory> + SubClass<T>,
{
if self.as_raw().is_class::<U>() {
Ok(unsafe { self.cast_unchecked() })
} else {
Err(self)
}
}
unsafe fn cast_unchecked<U>(self) -> Ref<U, Own>
where
U: GodotObject<Memory = T::Memory>,
{
let ret = Ref::move_from_sys(self.ptr.as_non_null());
std::mem::forget(self);
ret
}
#[inline]
pub fn cast_instance<C>(self) -> Option<Instance<C, Own>>
where
C: NativeClass<Base = T>,
{
self.try_cast_instance().ok()
}
#[inline]
pub fn try_cast_instance<C>(self) -> Result<Instance<C, Own>, Self>
where
C: NativeClass<Base = T>,
{
Instance::try_from_base(self)
}
}
impl<T: GodotObject> Ref<T, Shared> {
#[inline(always)]
pub unsafe fn assume_safe<'a, 'r>(&'r self) -> TRef<'a, T, Shared>
where
AssumeSafeLifetime<'a, 'r>: LifetimeConstraint<T::Memory>,
{
T::Memory::impl_assume_safe(self)
}
#[inline(always)]
pub unsafe fn assume_unique(self) -> Ref<T, Unique> {
T::Memory::impl_assume_unique(self)
}
}
impl<T: GodotObject<Memory = ManuallyManaged>> Ref<T, Shared> {
#[inline]
#[allow(clippy::trivially_copy_pass_by_ref)]
pub unsafe fn is_instance_sane(&self) -> bool {
let api = get_api();
if !(api.godot_is_instance_valid)(self.as_ptr()) {
return false;
}
self.as_raw_unchecked().is_class::<T>()
}
#[inline]
#[allow(clippy::trivially_copy_pass_by_ref)]
pub unsafe fn assume_safe_if_sane<'a>(&self) -> Option<TRef<'a, T, Shared>> {
if self.is_instance_sane() {
Some(self.assume_safe_unchecked())
} else {
None
}
}
#[inline]
pub unsafe fn assume_unique_if_sane(self) -> Option<Ref<T, Unique>> {
if self.is_instance_sane() {
Some(self.cast_access())
} else {
None
}
}
}
impl<T: GodotObject<Memory = RefCounted>> Ref<T, Shared> {
#[inline(always)]
pub unsafe fn assume_thread_local(self) -> Ref<T, ThreadLocal> {
self.cast_access()
}
}
impl<T: GodotObject<Memory = RefCounted>> Ref<T, Unique> {
#[inline(always)]
pub fn into_thread_local(self) -> Ref<T, ThreadLocal> {
unsafe { self.cast_access() }
}
}
impl<T: GodotObject> Ref<T, Unique> {
#[inline(always)]
pub fn into_shared(self) -> Ref<T, Shared> {
unsafe { self.cast_access() }
}
}
impl<T: GodotObject<Memory = ManuallyManaged>> Ref<T, Unique> {
#[inline]
pub fn free(self) {
unsafe {
self.as_raw().free();
}
}
}
impl<T: GodotObject<Memory = ManuallyManaged> + QueueFree> Ref<T, Unique> {
#[inline]
pub fn queue_free(self) {
unsafe { T::godot_queue_free(self.as_ptr()) }
}
}
impl<T: GodotObject, Own: Ownership> Eq for Ref<T, Own> {}
impl<T, Own, RhsOws> PartialEq<Ref<T, RhsOws>> for Ref<T, Own>
where
T: GodotObject,
Own: Ownership,
RhsOws: Ownership,
{
#[inline]
fn eq(&self, other: &Ref<T, RhsOws>) -> bool {
self.ptr.as_non_null() == other.ptr.as_non_null()
}
}
impl<T: GodotObject, Own: Ownership> Ord for Ref<T, Own> {
#[inline]
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.ptr.as_non_null().cmp(&other.ptr.as_non_null())
}
}
impl<T: GodotObject, Own: Ownership> PartialOrd for Ref<T, Own> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.ptr.as_non_null().partial_cmp(&other.ptr.as_non_null())
}
}
impl<T: GodotObject, Own: Ownership> Hash for Ref<T, Own> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_usize(self.ptr.as_ptr() as usize)
}
}
impl<T: GodotObject, Own: Ownership> Debug for Ref<T, Own> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}({:p})", T::class_name(), self.ptr.as_ptr())
}
}
impl<T: GodotObject, Own: Ownership> Ref<T, Own> {
#[doc(hidden)]
#[inline]
pub fn sys(&self) -> *mut sys::godot_object {
self.ptr.as_ptr()
}
#[doc(hidden)]
#[inline]
pub fn as_ptr(&self) -> *mut sys::godot_object {
self.ptr.as_ptr()
}
#[doc(hidden)]
#[inline]
pub unsafe fn as_raw_unchecked<'a>(&self) -> &'a RawObject<T> {
RawObject::from_sys_ref_unchecked(self.ptr.as_non_null())
}
#[doc(hidden)]
#[inline]
pub unsafe fn move_from_sys(obj: NonNull<sys::godot_object>) -> Self {
Ref {
ptr: <T::Memory as MemorySpec>::PtrWrapper::new(obj),
_marker: PhantomData,
}
}
#[doc(hidden)]
#[inline]
pub unsafe fn from_sys(obj: NonNull<sys::godot_object>) -> Self {
let ret = Self::move_from_sys(obj);
<T::Memory as MemorySpec>::maybe_add_ref(ret.as_raw_unchecked());
ret
}
#[doc(hidden)]
#[inline]
pub unsafe fn init_from_sys(obj: NonNull<sys::godot_object>) -> Self {
let ret = Self::move_from_sys(obj);
<T::Memory as MemorySpec>::maybe_init_ref(ret.as_raw_unchecked());
ret
}
unsafe fn cast_access<TargetOws: Ownership>(self) -> Ref<T, TargetOws> {
let ret = Ref::move_from_sys(self.ptr.as_non_null());
std::mem::forget(self);
ret
}
#[doc(hidden)]
#[inline(always)]
pub unsafe fn assume_safe_unchecked<'a>(&self) -> TRef<'a, T, Own> {
TRef::new(T::cast_ref(self.as_raw_unchecked()))
}
}
pub struct TRef<'a, T: GodotObject, Own: Ownership = Shared> {
obj: &'a T,
_marker: PhantomData<Own>,
}
impl<'a, T: GodotObject, Own: Ownership> Copy for TRef<'a, T, Own> {}
impl<'a, T: GodotObject, Own: Ownership> Clone for TRef<'a, T, Own> {
#[inline]
fn clone(&self) -> Self {
TRef::new(self.obj)
}
}
impl<'a, T: GodotObject, Own: Ownership> Debug for TRef<'a, T, Own> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}({:p})", T::class_name(), self.obj)
}
}
impl<'a, T: GodotObject, Own: Ownership> Deref for TRef<'a, T, Own> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
self.obj
}
}
impl<'a, T: GodotObject, Own: Ownership> AsRef<T> for TRef<'a, T, Own> {
#[inline]
fn as_ref(&self) -> &T {
self.obj
}
}
impl<'a, T: GodotObject, Own: Ownership> Borrow<T> for TRef<'a, T, Own> {
#[inline]
fn borrow(&self) -> &T {
self.obj
}
}
impl<'a, T: GodotObject, Own: Ownership> TRef<'a, T, Own> {
pub(crate) fn new(obj: &'a T) -> Self {
TRef {
obj,
_marker: PhantomData,
}
}
#[inline]
#[allow(clippy::should_implement_trait)]
pub fn as_ref(self) -> &'a T {
self.obj
}
#[inline]
pub fn cast<U>(self) -> Option<TRef<'a, U, Own>>
where
U: GodotObject + SubClass<T>,
{
self.obj.cast().map(TRef::new)
}
#[inline(always)]
pub fn upcast<U>(&self) -> TRef<'a, U, Own>
where
U: GodotObject,
T: SubClass<U>,
{
TRef::new(self.obj.upcast())
}
#[inline]
pub fn cast_instance<C>(self) -> Option<TInstance<'a, C, Own>>
where
C: NativeClass<Base = T>,
{
TInstance::try_from_base(self)
}
}
impl<'a, Kind, T, Own> TRef<'a, T, Own>
where
Kind: Memory,
T: GodotObject<Memory = Kind>,
Own: NonUniqueOwnership,
{
#[inline]
pub fn claim(self) -> Ref<T, Own> {
unsafe { Ref::from_sys(self.obj.as_raw().sys()) }
}
}
impl<'a, T: GodotObject> TRef<'a, T, Shared> {
#[inline]
pub unsafe fn try_from_instance_id(id: i64) -> Option<Self> {
let api = get_api();
let ptr = NonNull::new((api.godot_instance_from_id)(id as sys::godot_int))?;
let raw = RawObject::try_from_sys_ref(ptr)?;
Some(TRef::new(T::cast_ref(raw)))
}
#[inline]
pub unsafe fn from_instance_id(id: i64) -> Self {
Self::try_from_instance_id(id).expect("instance should be alive")
}
}
pub struct Null<T>(PhantomData<T>);
impl<T: GodotObject> Null<T> {
#[inline]
#[allow(clippy::self_named_constructors)]
pub fn null() -> Self {
Null(PhantomData)
}
}