godot_core/obj/base.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
/*
* Copyright (c) godot-rust; Bromeon and contributors.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
use crate::obj::{Gd, GodotClass};
use crate::{classes, sys};
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::mem::ManuallyDrop;
/// Restricted version of `Gd`, to hold the base instance inside a user's `GodotClass`.
///
/// Behaves similarly to [`Gd`][crate::obj::Gd], but is more constrained. Cannot be constructed by the user.
pub struct Base<T: GodotClass> {
// Like `Gd`, it's theoretically possible that Base is destroyed while there are still other Gd pointers to the underlying object. This is
// safe, may however lead to unintended behavior. The base_test.rs file checks some of these scenarios.
// Internal smart pointer is never dropped. It thus acts like a weak pointer and is needed to break reference cycles between Gd<T>
// and the user instance owned by InstanceStorage.
//
// There is no data apart from the opaque bytes, so no memory or resources to deallocate.
// When triggered by Godot/GDScript, the destruction order is as follows:
// 1. Most-derived Godot class (C++)
// ...
// 2. RefCounted (C++)
// 3. Object (C++) -- this triggers InstanceStorage destruction
// 4. Base<T>
// 5. User struct (GodotClass implementation)
// 6. InstanceStorage
//
// When triggered by Rust (Gd::drop on last strong ref), it's as follows:
// 1. Gd<T> -- triggers InstanceStorage destruction
// 2.
obj: ManuallyDrop<Gd<T>>,
}
impl<T: GodotClass> Base<T> {
/// "Copy constructor": allows to share a `Base<T>` weak pointer.
///
/// The return value is a weak pointer, so it will not keep the instance alive.
///
/// # Safety
/// `base` must be alive at the time of invocation, i.e. user `init()` (which could technically destroy it) must not have run yet.
/// If `base` is destroyed while the returned `Base<T>` is in use, that constitutes a logic error, not a safety issue.
pub(crate) unsafe fn from_base(base: &Base<T>) -> Base<T> {
debug_assert!(base.obj.is_instance_valid());
Base::from_obj(Gd::from_obj_sys_weak(base.obj.obj_sys()))
}
/// Create base from existing object (used in script instances).
///
/// The return value is a weak pointer, so it will not keep the instance alive.
///
/// # Safety
/// `gd` must be alive at the time of invocation. If it is destroyed while the returned `Base<T>` is in use, that constitutes a logic
/// error, not a safety issue.
pub(crate) unsafe fn from_gd(gd: &Gd<T>) -> Self {
debug_assert!(gd.is_instance_valid());
Base::from_obj(Gd::from_obj_sys_weak(gd.obj_sys()))
}
/// Create new base from raw Godot object.
///
/// The return value is a weak pointer, so it will not keep the instance alive.
///
/// # Safety
/// `base_ptr` must point to a valid, live object at the time of invocation. If it is destroyed while the returned `Base<T>` is in use,
/// that constitutes a logic error, not a safety issue.
pub(crate) unsafe fn from_sys(base_ptr: sys::GDExtensionObjectPtr) -> Self {
assert!(!base_ptr.is_null(), "instance base is null pointer");
// Initialize only as weak pointer (don't increment reference count)
let obj = Gd::from_obj_sys_weak(base_ptr);
// This obj does not contribute to the strong count, otherwise we create a reference cycle:
// 1. RefCounted (dropped in GDScript)
// 2. holds user T (via extension instance and storage)
// 3. holds Base<T> RefCounted (last ref, dropped in T destructor, but T is never destroyed because this ref keeps storage alive)
// Note that if late-init never happened on self, we have the same behavior (still a raw pointer instead of weak Gd)
Base::from_obj(obj)
}
fn from_obj(obj: Gd<T>) -> Self {
Self {
obj: ManuallyDrop::new(obj),
}
}
/// Returns a [`Gd`] referencing the same object as this reference.
///
/// Using this method to call methods on the base field of a Rust object is discouraged, instead use the
/// methods from [`WithBaseField`](super::WithBaseField) when possible.
#[doc(hidden)]
pub fn to_gd(&self) -> Gd<T> {
(*self.obj).clone()
}
// Currently only used in outbound virtual calls (for scripts); search for: base_field(self).obj_sys().
#[doc(hidden)]
pub fn obj_sys(&self) -> sys::GDExtensionObjectPtr {
self.obj.obj_sys()
}
}
impl<T: GodotClass> Debug for Base<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
classes::debug_string(&self.obj, f, "Base")
}
}
impl<T: GodotClass> Display for Base<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
classes::display_string(&self.obj, f)
}
}