godot::obj

Struct OnReady

pub struct OnReady<T> { /* private fields */ }
Expand description

Ergonomic late-initialization container with ready() support.

While deferred initialization is generally seen as bad practice, it is often inevitable in game development. Godot in particular encourages initialization inside ready(), e.g. to access the scene tree after a node is inserted into it. The alternative to using this pattern is Option<T>, which needs to be explicitly unwrapped with unwrap() or expect() each time.

OnReady<T> should always be used as a field. There are two modes to use it:

  1. Automatic mode, using new(), from_base_fn() or node().
    Before ready() is called, all OnReady fields constructed with the above methods are automatically initialized, in the order of declaration. This means that you can safely access them in ready().

  2. Manual mode, using manual().
    These fields are left uninitialized until you call init() on them. This is useful if you need more complex initialization scenarios than a closure allows. If you forget initialization, a panic will occur on first access.

Conceptually, OnReady<T> is very close to once_cell’s Lazy<T>, with additional hooks into the Godot lifecycle. The absence of methods to check initialization state is deliberate: you don’t need them if you follow the above two patterns. This container is not designed as a general late-initialization solution, but tailored to the ready() semantics of Godot.

OnReady<T> cannot be used with #[export] fields, because ready() is typically not called in the editor (unless #[class(tool)] is specified). You can however use it with #[var] – just make sure to access the fields in GDScript after ready().

This type is not thread-safe. ready() runs on the main thread, and you are expected to access its value on the main thread, as well.

§Requirements

  • The class must have an explicit Base field (i.e. base: Base<Node>).
  • The class must inherit Node (otherwise ready() would not exist anyway).

§Example - user-defined init

use godot::prelude::*;

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

#[godot_api]
impl INode for MyClass {
    fn init(base: Base<Node>) -> Self {
       Self {
           base,
           auto: OnReady::new(|| 11),
           manual: OnReady::manual(),
       }
    }

    fn ready(&mut self) {
       // self.auto is now ready with value 11.
       assert_eq!(*self.auto, 11);

       // self.manual needs to be initialized manually.
       self.manual.init(22);
       assert_eq!(*self.manual, 22);
    }
}

§Example - macro-generated init

use godot::prelude::*;

#[derive(GodotClass)]
#[class(init, base = Node)]
struct MyClass {
   base: Base<Node>,
   #[init(node = "ChildPath")]
   auto: OnReady<Gd<Node2D>>,
   #[init(val = OnReady::manual())]
   manual: OnReady<i32>,
}

#[godot_api]
impl INode for MyClass {
    fn ready(&mut self) {
       // self.node is now ready with the node found at path `ChildPath`.
       assert_eq!(self.auto.get_name(), "ChildPath".into());

       // self.manual needs to be initialized manually.
       self.manual.init(22);
       assert_eq!(*self.manual, 22);
    }
}

Implementations§

§

impl<T> OnReady<Gd<T>>
where T: GodotClass + Inherits<Node>,

pub fn node(path: impl AsArg<NodePath>) -> OnReady<Gd<T>>

Variant of OnReady::new(), fetching the node located at path before ready().

This is the functional equivalent of the GDScript pattern @onready var node = $NodePath.

§Panics
  • If path does not point to a valid node.

Note that the panic will only happen if and when the node enters the SceneTree for the first time (i.e.: it receives the READY notification).

§

impl<T> OnReady<T>

pub fn new<F>(init_fn: F) -> OnReady<T>
where F: FnOnce() -> T + 'static,

Schedule automatic initialization before ready().

This guarantees that the value is initialized once ready() starts running. Until then, accessing the object may panic. In particular, the object is not initialized on first use.

The value is also initialized when you don’t override ready().

For more control over initialization, use the OnReady::manual() constructor, followed by a self.init() call during ready().

pub fn from_base_fn<F>(init_fn: F) -> OnReady<T>
where F: FnOnce(&Gd<Node>) -> T + 'static,

Variant of OnReady::new(), allowing access to Base when initializing.

pub fn manual() -> OnReady<T>

Leave uninitialized, expects manual initialization during ready().

If you use this method, you must call init() during the ready() callback, otherwise a panic will occur.

pub fn init(&mut self, value: T)

Runs manual initialization.

§Panics
  • If init() was called before.
  • If this object was already provided with a closure during construction, in Self::new().

Trait Implementations§

§

impl<T> Debug for OnReady<T>
where T: Debug,

§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
§

impl<T> Deref for OnReady<T>

§

fn deref(&self) -> &<OnReady<T> as Deref>::Target

Returns a shared reference to the value.

§Panics

If the value is not yet initialized.

§

type Target = T

The resulting type after dereferencing.
§

impl<T> DerefMut for OnReady<T>

§

fn deref_mut(&mut self) -> &mut <OnReady<T> as Deref>::Target

Returns an exclusive reference to the value.

§Panics

If the value is not yet initialized.

§

impl<T> GodotConvert for OnReady<T>
where T: GodotConvert,

§

type Via = <T as GodotConvert>::Via

The type through which Self is represented in Godot.
§

impl<T> Var for OnReady<T>
where T: Var,

§

fn get_property(&self) -> <OnReady<T> as GodotConvert>::Via

§

fn set_property(&mut self, value: <OnReady<T> as GodotConvert>::Via)

§

fn var_hint() -> PropertyHintInfo

Specific property hints, only override if they deviate from GodotType::property_info, e.g. for enums/newtypes.

Auto Trait Implementations§

§

impl<T> Freeze for OnReady<T>
where T: Freeze,

§

impl<T> !RefUnwindSafe for OnReady<T>

§

impl<T> !Send for OnReady<T>

§

impl<T> !Sync for OnReady<T>

§

impl<T> Unpin for OnReady<T>
where T: Unpin,

§

impl<T> !UnwindSafe for OnReady<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.