Struct OnEditor

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

Exported property that must be initialized in the editor (or associated code) before use.

Use this type whenever your Rust code cannot provide a value for a field, but expects one to be specified in the Godot editor.

If you need automatic initialization during ready(), e.g. for loading nodes or resources, use OnReady<Gd<T>> instead. As a general “maybe initialized” type, Option<Gd<T>> is always available, even if more verbose.

§What consitutes “initialized”?

Whether a value is considered initialized or not depends on T.

  • For objects, a value is initialized if it is not null. Exported object propreties in Godot are nullable, but Gd<T> and DynGd<T, D> do not support nullability and can thus not directly be exported with #[export]. OnEditor can bridge this gap, by expecting users to set a non-null value, and panicking if they don’t.
  • For built-in types, a value is initialized if it is different from a user-selected sentinel value (e.g. -1).

More on this below (see also table-of-contents sidebar).

§Initialization semantics

Panics during access (Deref/DerefMut impls) if uninitialized.

When used inside a node class, OnEditor checks if a value has been set before ready() is run, and panics otherwise. This validation is performed for all OnEditor fields declared in a given GodotClass, regardless of whether they are #[var], #[export], or neither. Once initialized, OnEditor can be used almost as if it were a T value itself, due to Deref/DerefMut impls.

OnEditor<T> should always be used as a struct field, preferably in tandem with an #[export] or #[var]. Initializing OnEditor values via code before the first use is supported, but should be limited to use cases involving builder or factory patterns.

§Using OnEditor with classes

You can wrap class smart pointers Gd<T> and DynGd<T, D> inside OnEditor, to make them exportable. Gd<T> itself does not implement the Export trait.

§Example: automatic init

This example uses the Default impl, which expects a non-null value to be provided.

#[derive(GodotClass)]
#[class(init, base = Node)]
struct ResourceHolder {
    #[export]
    editor_property: OnEditor<Gd<Resource>>,
}

#[godot_api]
impl INode for ResourceHolder {
    fn ready(&mut self) {
        // Will always be valid and **must** be set via editor.
        // Additional check is being run before ready(),
        // to ensure that given value can't be null.
        let some_variant = self.editor_property.get_meta("SomeName");
    }
}

§Example: user-defined init

Uninitialized OnEditor<Gd<T>> and OnEditor<DynGd<T, D>> can be created with OnEditor::default().

#[derive(GodotClass)]
#[class(base = Node)]
struct NodeHolder {
    #[export]
    required_node: OnEditor<Gd<Node>>,

    base: Base<Node>
}

#[godot_api]
impl INode for NodeHolder {
    fn init(base: Base<Node>) -> Self {
       Self {
           base,
           required_node: OnEditor::default(),
       }
    }
}

§Example: factory pattern

#[derive(GodotClass)]
#[class(init, base = Node)]
struct NodeHolder {
    #[export]
    required_node: OnEditor<Gd<Node>>,
}

fn create_and_add(
    mut this: Gd<Node>,
    some_class_scene: Gd<PackedScene>,
    some_node: Gd<Node>,
) -> Gd<NodeHolder> {
    let mut my_node = some_class_scene.instantiate_as::<NodeHolder>();

    // Would cause a panic:
    // this.add_child(&my_node);

    // It's possible to initialize the value programmatically, although typically
    // it is set in the editor and stored in a .tscn file.
    // Note: nodes are manually managed and leak memory unless tree-attached or freed.
    my_node.bind_mut().required_node.init(some_node);

    // Will not panic, since the node is initialized now.
    this.add_child(&my_node);

    my_node
}

§Using OnEditor with built-in types

OnEditor<T> can be used with any #[export]-enabled builtins, to provide domain-specific validation logic. An example might be to check whether a game entity has been granted a non-zero ID.

To detect whether a value has been set in the editor, OnEditor<T> uses a sentinel value. This is a special marker value for “uninitialized” and is selected by the user. For example, a sentinel value of -1 or 0 might be used to represent an uninitialized i32.

There is deliberately no Default implementation for OnEditor with builtins, as the sentinel is highly domain-specific.

§Example

use godot::prelude::*;

#[derive(GodotClass)]
#[class(init, base = Node)]
struct IntHolder {
    // Uninitialized value will be represented by `42` in the editor.
    // Will cause panic if not set via the editor or code before use.
    #[export]
    #[init(sentinel = 42)]
    some_primitive: OnEditor<i64>,
}

fn create_and_add(mut this: Gd<Node>, val: i64) -> Gd<IntHolder> {
    let mut my_node = IntHolder::new_alloc();

    // Would cause a panic:
    // this.add_child(&my_node);

    // It's possible to initialize the value programmatically, although typically
    // it is set in the editor and stored in a .tscn file.
    my_node.bind_mut().some_primitive.init(val);

    // Will not panic, since the node is initialized now.
    this.add_child(&my_node);

    my_node
}

§Using OnEditor with #[class(tool)]

When used with #[class(tool)], the before-ready checks are omitted. Otherwise, OnEditor<T> behaves the same — accessing an uninitialized value will cause a panic.

Implementations§

§

impl<T> OnEditor<T>
where T: Var + FromGodot + PartialEq,

OnEditor<T> is usable only for properties – which is enforced via Var and FromGodot bounds.

Furthermore, PartialEq is needed to compare against uninitialized sentinel values.

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

Initializes invalid OnEditor<T> with given value.

§Panics

If init() was called before.

pub fn from_sentinel(val: T) -> OnEditor<T>

Creates new OnEditor<T> with a value that is considered invalid.

If this value is not changed in the editor, accessing it from Rust will cause a panic.

Trait Implementations§

§

impl<T, D> Default for OnEditor<DynGd<T, D>>
where T: GodotClass, D: 'static + ?Sized,

§

fn default() -> OnEditor<DynGd<T, D>>

Returns the “default value” for a type. Read more
§

impl<T> Default for OnEditor<Gd<T>>
where T: GodotClass,

§

fn default() -> OnEditor<Gd<T>>

Returns the “default value” for a type. Read more
§

impl<T> Deref for OnEditor<T>

§

type Target = T

The resulting type after dereferencing.
§

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

Dereferences the value.
§

impl<T> DerefMut for OnEditor<T>

§

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

Mutably dereferences the value.
§

impl<T, D> Export for OnEditor<DynGd<T, D>>
where OnEditor<DynGd<T, D>>: Var, T: GodotClass<Exportable = Yes> + Bounds, D: 'static + ?Sized,

#[export] for OnEditor<DynGd<T, D>> is available only for T being Engine class (such as Node or Resource).

Consider exporting OnEditor<Gd<T>> instead of OnEditor<DynGd<T, D>> for user-declared GDExtension classes.

§

fn export_hint() -> PropertyHintInfo

The export info to use for an exported field of this type, if no other export info is specified.
§

impl<T> Export for OnEditor<Gd<T>>
where OnEditor<Gd<T>>: Var, T: GodotClass<Exportable = Yes> + Bounds,

§

fn export_hint() -> PropertyHintInfo

The export info to use for an exported field of this type, if no other export info is specified.
§

impl<T> Export for OnEditor<T>

§

fn export_hint() -> PropertyHintInfo

The export info to use for an exported field of this type, if no other export info is specified.
§

impl<T, D> GodotConvert for OnEditor<DynGd<T, D>>
where T: GodotClass, D: ?Sized,

§

type Via = Option<<DynGd<T, D> as GodotConvert>::Via>

The type through which Self is represented in Godot.
§

impl<T> GodotConvert for OnEditor<Gd<T>>

§

type Via = Option<<Gd<T> as GodotConvert>::Via>

The type through which Self is represented in Godot.
§

impl<T> GodotConvert for OnEditor<T>

§

type Via = <T as GodotConvert>::Via

The type through which Self is represented in Godot.
§

impl<T, D> Var for OnEditor<DynGd<T, D>>
where T: GodotClass, D: 'static + ?Sized,

§

fn get_property(&self) -> <OnEditor<DynGd<T, D>> as GodotConvert>::Via

§

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

§

fn var_hint() -> PropertyHintInfo

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

impl<T> Var for OnEditor<Gd<T>>
where T: GodotClass,

§

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

§

fn set_property(&mut self, value: <OnEditor<Gd<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.
§

impl<T> Var for OnEditor<T>

§

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

§

fn set_property(&mut self, value: <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.
§

impl<T> BuiltinExport for OnEditor<T>

Auto Trait Implementations§

§

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

§

impl<T> RefUnwindSafe for OnEditor<T>
where T: RefUnwindSafe,

§

impl<T> Send for OnEditor<T>
where T: Send,

§

impl<T> Sync for OnEditor<T>
where T: Sync,

§

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

§

impl<T> UnwindSafe for OnEditor<T>
where T: UnwindSafe,

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<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
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.