Struct godot::obj::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().
    Before ready() is called, all OnReady fields constructed with new() 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.

§Example

use godot::prelude::*;

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

#[godot_api]
impl INode for MyClass {
    fn init(_base: Base<Node>) -> Self {
       Self {
           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);
    }
}

Implementations§

§

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 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> 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,

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>,

§

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>,

§

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.