Skip to main content

WithBaseField

Trait WithBaseField 

pub trait WithBaseField: GodotClass<Declarer = DeclUser> + Bounds {
    // Required method
    fn to_gd(&self) -> Gd<Self>;

    // Provided methods
    fn base(&self) -> BaseRef<'_, Self> { ... }
    fn base_mut(&mut self) -> BaseMut<'_, Self> { ... }
    fn unbind<R, F>(&mut self, scope: F) -> R
       where F: FnOnce(&mut Gd<Self::Base>) -> R { ... }
    fn run_deferred<F>(&mut self, mut_self_method: F)
       where F: FnOnce(&mut Self) + 'static { ... }
    fn run_deferred_gd<F>(&mut self, gd_function: F)
       where F: FnOnce(Gd<Self>) + 'static { ... }
}
Expand description

Trait that is automatically implemented for user classes containing a Base<T> field.

Gives direct access to the containing Gd<Self> from self.

§Usage as a bound

In order to call base() or base_mut() within a function or on a type you define, you need a WithBaseField<Base = T> bound, where T is the base class of your type.

fn some_fn<T>(value: &T)
where
    T: WithBaseField<Base = Node3D>,
{
    let base = value.base();
    let pos = base.get_position();
}

Required Methods§

fn to_gd(&self) -> Gd<Self>

Returns the Gd pointer containing this object.

This is intended to be stored or passed to engine methods. You cannot call bind() or bind_mut() on it, while the method calling to_gd() is still running; that would lead to a double borrow panic.

§Panics

If called during initialization (the init() function or Gd::from_init_fn()). Use Base::to_init_gd() instead.

Provided Methods§

fn base(&self) -> BaseRef<'_, Self>

Returns a shared reference guard, suitable for calling &self engine methods on this object.

Holding a shared guard prevents other code paths from obtaining a mutable reference to self, as such it is recommended to drop the guard as soon as you no longer need it.

§Examples
use godot::prelude::*;

#[derive(GodotClass)]
#[class(init, base=Node)]
struct MyClass {
    base: Base<Node>,
}

#[godot_api]
impl INode for MyClass {
    fn process(&mut self, _delta: f32) {
        let name = self.base().get_name();
        godot_print!("name is {name}");
    }
}

However, we cannot call methods that require &mut Base, such as Node::add_child().

ⓘ
use godot::prelude::*;

#[derive(GodotClass)]
#[class(init, base = Node)]
struct MyClass {
    ///     base: Base<Node>,
}

#[godot_api]
impl INode for MyClass {
    fn process(&mut self, _delta: f32) {
        let node = Node::new_alloc();
        // fails because `add_child` requires a mutable reference.
        self.base().add_child(&node);
    }
}

For this, use base_mut() instead.

fn base_mut(&mut self) -> BaseMut<'_, Self>

Returns an exclusive reference guard, suitable for calling &self/&mut self engine methods on this object.

This method will allow you to call back into the same object from Godot – something that to_gd() does not allow. You have to keep the BaseMut guard bound for the entire duration the engine might re-enter a function of your class. The guard temporarily absorbs the &mut self reference, which allows for an additional exclusive (mutable) reference to be acquired.

Holding an exclusive guard prevents other code paths from obtaining any reference to self, as such it is recommended to drop the guard as soon as you no longer need it.

If you need an entire scope where &mut self can be accessed from outside, use unbind().

§Examples
#[derive(GodotClass)]
#[class(init, base = Node)]
struct MyClass {
    base: Base<Node>,
}

#[godot_api]
impl INode for MyClass {
    fn process(&mut self, _delta: f32) {
        let node = Node::new_alloc();
        self.base_mut().add_child(&node);
    }
}

We can call back into self through Godot:

#[derive(GodotClass)]
#[class(init, base=Node)]
struct MyClass {
    base: Base<Node>,
}

#[godot_api]
impl INode for MyClass {
    fn process(&mut self, _delta: f32) {
        self.base_mut().call("other_method", &[]);
    }
}

#[godot_api]
impl MyClass {
    #[func]
    fn other_method(&mut self) {}
}

Rust’s borrow checking rules are enforced if you try to overlap base_mut() calls:

ⓘ
// error[E0499]: cannot borrow `*self` as mutable more than once at a time

fn method(&mut self) {
    let mut a = self.base_mut();
    //          ---- first mutable borrow occurs here
    let mut b = self.base_mut();
    //          ^^^^ second mutable borrow occurs here
}

fn unbind<R, F>(&mut self, scope: F) -> R
where F: FnOnce(&mut Gd<Self::Base>) -> R,

Release exclusive self borrow during scope, for reentrant access to &mut self.

Opposite of Gd::bind_mut(): trades an exclusive borrow (&mut self) for a Gd pointer + the option to reentrantly access the Rust object (through Godot). As unbind takes &mut self, the Rust compiler guarantees no other borrow can exist.

// This code:
self.unbind(|this| code(this));

// is equivalent to:
{
    let mut guard = self.base_mut();
    code(&mut guard); // DerefMut to &mut Gd<Self::Base>.
} // guard dropped here.
§Example: reentrant signal

A Player owns a Weapon. If that weapon is out of ammo, an out_of_ammo signal is emitted, which links back to the Player::reload method. Now if Player::shoot(&mut self) causes the weapon to be empty, that callback needs to access &mut self again. This wouldn’t normally work since it’s already borrowed, but unbind() explicitly allows it.

#[derive(GodotClass)]
#[class(init, base = Node)]
struct Player {
    #[init(node = "Weapon")]
    weapon: OnReady<Gd<Weapon>>,
    base: Base<Node>,
}

#[godot_api]
impl INode for Player {
    fn ready(&mut self) {
        self.weapon.signals()
            .out_of_ammo()
            .connect_other(&*self, Self::reload);
    }
}

#[godot_api]
impl Player {
    fn reload(&mut self) { /* ... */ }

    fn shoot(&mut self) {
        // Copy Gd<Weapon> which isn't tied to `self` (no borrows).
        let mut weapon = self.weapon.clone();

        // Weapon::fire() can trigger Player::reload(). We already
        // borrow &mut self here, so without unbind() this panics.
        self.unbind(|_| weapon.bind_mut().fire());
    }
}
§Example: dynamic calls through Godot VM

Hidden turrets pop up when an alarm is raised. Turret::raise_alarm() notifies all turrets in the group via call_group(), which re-enters on_alarm() on self. Then set_visible() synchronously sends the VISIBILITY_CHANGED notification, again reentrantly.

#[derive(GodotClass)]
#[class(init, base = Node2D)]
struct Turret {
    base: Base<Node2D>,
}

#[godot_api]
impl Turret {
    #[func]
    fn on_alarm(&mut self) {}

    fn raise_alarm(&mut self) {
        self.unbind(|base| {
            base.get_tree().call_group("turrets", "on_alarm", &[]); // calls self.on_alarm().
            base.set_visible(true); // calls self.on_notification().
        });
    }
}

#[godot_api]
impl INode2D for Turret {
    fn on_notification(&mut self, what: CanvasItemNotification) {
        if what == CanvasItemNotification::VISIBILITY_CHANGED {
            // Refresh visuals.
        }
    }
}

fn run_deferred<F>(&mut self, mut_self_method: F)
where F: FnOnce(&mut Self) + 'static,

Defers the given closure to run during idle time.

This is a type-safe alternative to Object::call_deferred(). The closure receives &mut Self allowing direct access to Rust fields and methods.

See also Gd::run_deferred() to defer logic outside of self.

§Panics

If called outside the main thread.

fn run_deferred_gd<F>(&mut self, gd_function: F)
where F: FnOnce(Gd<Self>) + 'static,

Defers the given closure to run during idle time.

This is a type-safe alternative to Object::call_deferred(). The closure receives Gd<Self>, which can be used to call engine methods or bind()/bind_mut() to access the Rust object.

See also Gd::run_deferred_gd() to defer logic outside of self.

§Panics

If called outside the main thread.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§