godot_core/obj/dyn_gd.rs
1/*
2 * Copyright (c) godot-rust; Bromeon and contributors.
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 */
7
8use std::{fmt, ops};
9
10use crate::builtin::Variant;
11use crate::meta::error::ConvertError;
12use crate::meta::{ClassId, FromGodot, GodotConvert, PropertyHintInfo, ToGodot};
13use crate::obj::guards::DynGdRef;
14use crate::obj::{bounds, AsDyn, Bounds, DynGdMut, Gd, GodotClass, Inherits, OnEditor};
15use crate::registry::class::{get_dyn_property_hint_string, try_dynify_object};
16use crate::registry::property::{object_export_element_type_string, Export, Var};
17use crate::{meta, sys};
18
19/// Smart pointer integrating Rust traits via `dyn` dispatch.
20///
21/// `DynGd<T, D>` extends a Godot object [`Gd<T>`] with functionality for Rust's trait dynamic dispatch. \
22/// In this context, the type parameters have the following meaning:
23/// - `T` is the Godot class.
24/// - `D` is a trait object `dyn Trait`, where `T: Trait`.
25///
26/// To register the `T` -> `D` relation with godot-rust, `T` must implement [`AsDyn<D>`]. This can be automated with the
27/// [`#[godot_dyn]`](../register/attr.godot_dyn.html) attribute macro.
28///
29/// # Construction and API
30///
31/// You can convert between `Gd` and `DynGd` using [`Gd::into_dyn()`] and [`DynGd::into_gd()`]. The former sometimes needs an explicit
32/// `::<dyn Trait>` type argument, but can often be inferred.
33///
34/// The `DynGd` API is very close to `Gd`. In fact, both `Deref` and `DerefMut` are implemented for `DynGd` -> `Gd`, so you can access all the
35/// underlying `Gd` methods as well as Godot class APIs directly.
36///
37/// The main new parts are two methods [`dyn_bind()`][Self::dyn_bind] and [`dyn_bind_mut()`][Self::dyn_bind_mut]. These are very similar to `Gd`'s
38/// [`bind()`][Gd::bind] and [`bind_mut()`][Gd::bind_mut], but return a reference guard to the trait object `D` instead of the Godot class `T`.
39///
40/// # Example
41///
42/// ```no_run
43/// use godot::obj::{Gd, DynGd,NewGd};
44/// use godot::register::{godot_dyn, GodotClass};
45/// use godot::classes::RefCounted;
46///
47/// #[derive(GodotClass)]
48/// #[class(init)]
49/// struct Monster {
50/// #[init(val = 100)]
51/// hitpoints: u16,
52/// }
53///
54/// trait Health {
55/// fn is_alive(&self) -> bool;
56/// fn deal_damage(&mut self, damage: u16);
57/// }
58///
59/// // The #[godot_dyn] attribute macro registers the dynamic relation in godot-rust.
60/// // Traits are implemented as usual.
61/// #[godot_dyn]
62/// impl Health for Monster {
63/// fn is_alive(&self) -> bool {
64/// self.hitpoints > 0
65/// }
66///
67/// fn deal_damage(&mut self, damage: u16) {
68/// self.hitpoints = self.hitpoints.saturating_sub(damage);
69/// }
70/// }
71///
72/// // Create a Gd<Monster> and convert it -> DynGd<Monster, dyn Health>.
73/// let monster = Monster::new_gd();
74/// let dyn_monster = monster.into_dyn::<dyn Health>();
75///
76/// // Now upcast it to its base class -> type is DynGd<RefCounted, dyn Health>.
77/// let mut dyn_monster = dyn_monster.upcast::<RefCounted>();
78///
79/// // Due to RefCounted abstraction, you can no longer access concrete Monster properties.
80/// // However, the trait Health is still accessible through dyn_bind().
81/// assert!(dyn_monster.dyn_bind().is_alive());
82///
83/// // To mutate the object, call dyn_bind_mut(). Rust borrow rules apply.
84/// let mut guard = dyn_monster.dyn_bind_mut();
85/// guard.deal_damage(120);
86/// assert!(!guard.is_alive());
87/// ```
88///
89/// # Polymorphic `dyn` re-enrichment
90///
91/// When passing `DynGd<T, D>` to Godot, you will lose the `D` part of the type inside the engine, because Godot doesn't know about Rust traits.
92/// The trait methods won't be accessible through GDScript, either.
93///
94/// When _receiving_ objects from Godot, the [`FromGodot`] trait is used to convert values to their Rust counterparts. `FromGodot` allows you to
95/// use types in `#[func]` parameters or extract elements from arrays, among others. If you now receive a trait-enabled object back from Godot,
96/// you can easily obtain it as `Gd<T>` -- but what if you need the original `DynGd<T, D>` back? If `T` is concrete and directly implements `D`,
97/// then [`Gd::into_dyn()`] is of course possible. But in reality, you may have a polymorphic base class such as `RefCounted` or `Node` and
98/// want to ensure that trait object `D` dispatches to the correct subclass, without manually checking every possible candidate.
99///
100/// To stay with the above example: let's say `Health` is implemented for two classes `Monster` and `Knight`. You now have a
101/// `DynGd<RefCounted, dyn Health>`, which can represent either of the two classes. We pass this to Godot (e.g. as a `Variant`), and then back.
102///
103/// ```no_run
104/// # use godot::prelude::*;
105/// trait Health { /* ... */ }
106///
107/// #[derive(GodotClass)]
108/// # #[class(init)]
109/// struct Monster { /* ... */ }
110/// #[godot_dyn]
111/// impl Health for Monster { /* ... */ }
112///
113/// #[derive(GodotClass)]
114/// # #[class(init)]
115/// struct Knight { /* ... */ }
116/// #[godot_dyn]
117/// impl Health for Knight { /* ... */ }
118///
119/// // Let's construct a DynGd, and pass it to Godot as a Variant.
120/// # let runtime_condition = true;
121/// let variant = if runtime_condition {
122/// // DynGd<Knight, dyn Health>
123/// Knight::new_gd().into_dyn::<dyn Health>().to_variant()
124/// } else {
125/// // DynGd<Monster, dyn Health>
126/// Monster::new_gd().into_dyn::<dyn Health>().to_variant()
127/// };
128///
129/// // Now convert back into a DynGd -- but we don't know the concrete type.
130/// // We can still represent it as DynGd<RefCounted, dyn Health>.
131/// let dyn_gd: DynGd<RefCounted, dyn Health> = variant.to();
132/// // Now work with the abstract object as usual.
133/// ```
134///
135/// Any `Gd<T>` where `T` is an engine class can attempt conversion to `DynGd<T, D>` with [`Gd::try_dynify()`] as well.
136///
137/// ```no_run
138/// # use godot::prelude::*;
139/// # use godot::classes::Node2D;
140/// # // ShapeCast2D is marked as experimental and thus not included in the doctests.
141/// # // We use this mock to showcase some real-world usage.
142/// # struct FakeShapeCastCollider2D {}
143///
144/// # impl FakeShapeCastCollider2D {
145/// # fn get_collider(&self, _idx: i32) -> Option<Gd<Node2D>> { Some(Node2D::new_alloc()) }
146/// # }
147///
148/// trait Pushable { /* ... */ }
149///
150/// # let my_shapecast = FakeShapeCastCollider2D {};
151/// # let idx = 1;
152/// // We can try to convert `Gd<T>` into `DynGd<T, D>`.
153/// let node: Option<DynGd<Node2D, dyn Pushable>> =
154/// my_shapecast.get_collider(idx).and_then(
155/// |obj| obj.try_dynify().ok()
156/// );
157///
158/// // An object is returned after failed conversion, similarly to `Gd::try_cast()`.
159/// # let some_node = Node::new_alloc();
160/// match some_node.try_dynify::<dyn Pushable>() {
161/// Ok(dyn_gd) => (),
162/// Err(some_node) => godot_warn!("Failed to convert {some_node} into dyn Pushable!"),
163/// }
164/// ```
165///
166/// When converting from Godot back into `DynGd`, we say that the `dyn Health` trait object is _re-enriched_.
167///
168/// godot-rust achieves this thanks to the registration done by `#[godot_dyn]`: the library knows for which classes `Health` is implemented,
169/// and it can query the dynamic type of the object. Based on that type, it can find the `impl Health` implementation matching the correct class.
170/// Behind the scenes, everything is wired up correctly so that you can restore the original `DynGd` even after it has passed through Godot.
171///
172/// # Exporting
173///
174/// [Like `Gd<T>`](struct.Gd.html#exporting), using `#[export]` with `DynGd<T, D>` is possible only via [`OnEditor`] or [`Option`].
175/// `DynGd<T, D>` can also be exported directly as an element of an array such as `Array<DynGd<T, D>>`.
176///
177/// When talking about "exporting", the following paragraphs assume that you wrap `DynGd` in one of those types.
178///
179/// In cases where `T: AsDyn<D>` (the trait is directly implemented on the user class, i.e. no upcasting), exporting `DynGd<T, D>` is
180/// equivalent to exporting `Gd<T>` regarding Inspector UI.
181///
182/// ## Node-based classes
183///
184/// If `T` inherits `Node`, exporting `DynGd<T, D>` works identically to `Gd<T>`.
185///
186/// If you try to assign a class from the editor that does not implement trait `D`, Godot will report a conversion-failed error,
187/// but it will only do so when accessing the given value.
188///
189/// ## Resource-based classes
190///
191/// If `T` inherits `Resource`, exporting `DynGd<T, D>>` will limit the available choices to known implementors of the trait `D`.
192///
193/// For example, let's say you have four Rust classes:
194///
195/// | Class | Inherits | Implements trait |
196/// |--------------|------------|------------------|
197/// | `Bullet` | `Resource` | `Projectile` |
198/// | `Rocket` | `Resource` | `Projectile` |
199/// | `BulletNode` | `Node` | `Projectile` |
200/// | `Tower` | `Resource` | (none) |
201///
202/// Then, an exported `DynGd<Resource, dyn Projectile>` would be visible in Godot's Inspector UI with a drop-down field, i.e. users can assign
203/// only objects of certain classes. **The available options for the drop-down are `Bullet` and `Rocket`.** The class `BulletNode` is not
204/// available because it's not a `Resource`, and `Tower` is not because it doesn't implement the `Projectile` trait.
205///
206/// # Type inference
207///
208/// If a class implements more than one `AsDyn<D>` relation (usually via `#[godot_dyn]`), type inference will only work when the trait
209/// used for `D` explicitly declares a `: 'static` bound.
210/// Otherwise, if only one `impl AsDyn` is present for a given class, the type can always be inferred.
211///
212/// ```no_run
213/// # use godot::prelude::*;
214/// trait Health: 'static { /* ... */ }
215///
216/// // Exact equivalent to:
217/// trait OtherHealth
218/// where
219/// Self: 'static
220/// { /* ... */ }
221///
222/// trait NoInference { /* ... */ }
223///
224/// #[derive(GodotClass)]
225/// # #[class(init)]
226/// struct Monster { /* ... */ }
227///
228/// #[godot_dyn]
229/// impl Health for Monster { /* ... */ }
230///
231/// #[godot_dyn]
232/// impl NoInference for Monster { /* ... */ }
233///
234/// // Two example functions accepting trait object, to check type inference.
235/// fn deal_damage(h: &mut dyn Health) { /* ... */ }
236/// fn no_inference(i: &mut dyn NoInference) { /* ... */ }
237///
238/// // Type can be inferred since 'static bound is explicitly declared for Health trait.
239/// let mut dyn_gd = Monster::new_gd().into_dyn();
240/// deal_damage(&mut *dyn_gd.dyn_bind_mut());
241///
242/// // Otherwise type can't be properly inferred.
243/// let mut dyn_gd = Monster::new_gd().into_dyn::<dyn NoInference>();
244/// no_inference(&mut *dyn_gd.dyn_bind_mut());
245/// ```
246///
247/// ```compile_fail
248/// # use godot::prelude::*;
249/// trait Health { /* ... */ }
250///
251/// trait OtherTrait { /* ... */ }
252///
253/// #[derive(GodotClass)]
254/// # #[class(init)]
255/// struct Monster { /* ... */ }
256/// #[godot_dyn]
257/// impl Health for Monster { /* ... */ }
258/// #[godot_dyn]
259/// impl OtherTrait for Monster { /* ... */ }
260///
261/// fn deal_damage(h: &mut dyn Health) { /* ... */ }
262///
263/// // Type can't be inferred.
264/// // Would result in confusing compilation error
265/// // since compiler would try to enforce 'static *lifetime* (&'static mut ...) on our reference.
266/// let mut dyn_gd = Monster::new_gd().into_dyn();
267/// deal_damage(&mut *dyn_gd.dyn_bind_mut());
268/// ```
269pub struct DynGd<T, D>
270where
271 // T does _not_ require AsDyn<D> here. Otherwise, it's impossible to upcast (without implementing the relation for all base classes).
272 T: GodotClass,
273 D: ?Sized + 'static,
274{
275 // Potential optimizations: use single Gd; use Rc/Arc instead of Box+clone; store a downcast fn from Gd<T>; ...
276 obj: Gd<T>,
277 erased_obj: Box<dyn ErasedGd<D>>,
278}
279
280impl<T, D> DynGd<T, D>
281where
282 T: AsDyn<D> + Bounds<Declarer = bounds::DeclUser>,
283 D: ?Sized + 'static,
284{
285 pub(crate) fn from_gd(gd_instance: Gd<T>) -> Self {
286 let erased_obj = Box::new(gd_instance.clone());
287
288 Self {
289 obj: gd_instance,
290 erased_obj,
291 }
292 }
293}
294
295impl<T, D> DynGd<T, D>
296where
297 // Again, T deliberately does not require AsDyn<D> here. See above.
298 T: GodotClass,
299 D: ?Sized + 'static,
300{
301 /// Acquires a shared reference guard to the trait object `D`.
302 ///
303 /// The resulting guard implements `Deref<Target = D>`, allowing shared access to the trait's methods.
304 ///
305 /// See [`Gd::bind()`][Gd::bind] for borrow checking semantics and panics.
306 pub fn dyn_bind(&self) -> DynGdRef<'_, D> {
307 self.erased_obj.dyn_bind()
308 }
309
310 /// Acquires an exclusive reference guard to the trait object `D`.
311 ///
312 /// The resulting guard implements `DerefMut<Target = D>`, allowing exclusive mutable access to the trait's methods.
313 ///
314 /// See [`Gd::bind_mut()`][Gd::bind_mut] for borrow checking semantics and panics.
315 pub fn dyn_bind_mut(&mut self) -> DynGdMut<'_, D> {
316 self.erased_obj.dyn_bind_mut()
317 }
318
319 // Certain methods "overridden" from deref'ed Gd here, so they're more idiomatic to use.
320 // Those taking self by value, like free(), must be overridden.
321
322 /// **Upcast** to a Godot base, while retaining the `D` trait object.
323 ///
324 /// This is useful when you want to gather multiple objects under a common Godot base (e.g. `Node`), but still enable common functionality.
325 /// The common functionality is still accessible through `D` even when upcasting.
326 ///
327 /// See also [`Gd::upcast()`].
328 pub fn upcast<Base>(self) -> DynGd<Base, D>
329 where
330 Base: GodotClass,
331 T: Inherits<Base>,
332 {
333 DynGd {
334 obj: self.obj.upcast::<Base>(),
335 erased_obj: self.erased_obj,
336 }
337 }
338
339 /// **Downcast** to a more specific Godot class, while retaining the `D` trait object.
340 ///
341 /// If `T`'s dynamic type is not `Derived` or one of its subclasses, `Err(self)` is returned, meaning you can reuse the original
342 /// object for further casts.
343 ///
344 /// See also [`Gd::try_cast()`].
345 pub fn try_cast<Derived>(self) -> Result<DynGd<Derived, D>, Self>
346 where
347 Derived: Inherits<T>,
348 {
349 match self.obj.try_cast::<Derived>() {
350 Ok(obj) => Ok(DynGd {
351 obj,
352 erased_obj: self.erased_obj,
353 }),
354 Err(obj) => Err(DynGd {
355 obj,
356 erased_obj: self.erased_obj,
357 }),
358 }
359 }
360
361 /// ⚠️ **Downcast:** to a more specific Godot class, while retaining the `D` trait object.
362 ///
363 /// See also [`Gd::cast()`].
364 ///
365 /// # Panics
366 /// If the class' dynamic type is not `Derived` or one of its subclasses. Use [`Self::try_cast()`] if you want to check the result.
367 pub fn cast<Derived>(self) -> DynGd<Derived, D>
368 where
369 Derived: Inherits<T>,
370 {
371 self.try_cast().unwrap_or_else(|from_obj| {
372 panic!(
373 "downcast from {from} to {to} failed; instance {from_obj:?}",
374 from = T::class_id(),
375 to = Derived::class_id(),
376 )
377 })
378 }
379
380 /// Unsafe fast downcasts, no trait bounds.
381 ///
382 /// # Safety
383 /// The caller must ensure that the dynamic type of the object is `Derived` or a subclass of `Derived`.
384 // Not intended for public use. The lack of bounds simplifies godot-rust implementation, but adds another unsafety layer.
385 #[deny(unsafe_op_in_unsafe_fn)]
386 pub(crate) unsafe fn cast_unchecked<Derived>(self) -> DynGd<Derived, D>
387 where
388 Derived: GodotClass,
389 {
390 let cast_obj = self.obj.owned_cast::<Derived>();
391
392 // SAFETY: ensured by safety invariant.
393 let cast_obj = unsafe { cast_obj.unwrap_unchecked() };
394
395 DynGd {
396 obj: cast_obj,
397 erased_obj: self.erased_obj,
398 }
399 }
400
401 /// Downgrades to a `Gd<T>` pointer, abandoning the `D` abstraction.
402 #[must_use]
403 pub fn into_gd(self) -> Gd<T> {
404 self.obj
405 }
406
407 /// Represents `null` when passing a dynamic object argument to Godot.
408 ///
409 /// See [`Gd::null_arg()`]
410 pub fn null_arg() -> impl meta::AsArg<Option<DynGd<T, D>>> {
411 meta::NullArg(std::marker::PhantomData)
412 }
413}
414
415impl<T, D> DynGd<T, D>
416where
417 T: GodotClass + Bounds<Memory = bounds::MemManual>,
418 D: ?Sized + 'static,
419{
420 /// Destroy the manually-managed Godot object.
421 ///
422 /// See [`Gd::free()`] for semantics and panics.
423 pub fn free(self) {
424 self.obj.free()
425 }
426}
427
428// Don't derive since that messes with bounds, and `.clone()` may silently fall back to deref'ed `Gd::clone()`.
429impl<T, D> Clone for DynGd<T, D>
430where
431 T: GodotClass,
432 D: ?Sized + 'static,
433{
434 fn clone(&self) -> Self {
435 Self {
436 obj: self.obj.clone(),
437 erased_obj: self.erased_obj.clone_box(),
438 }
439 }
440}
441
442impl<T, D> PartialEq for DynGd<T, D>
443where
444 T: GodotClass,
445 D: ?Sized,
446{
447 fn eq(&self, other: &Self) -> bool {
448 self.obj == other.obj
449 }
450}
451
452impl<T, D> Eq for DynGd<T, D>
453where
454 T: GodotClass,
455 D: ?Sized,
456{
457}
458
459impl<T, D> std::hash::Hash for DynGd<T, D>
460where
461 T: GodotClass,
462 D: ?Sized,
463{
464 /// ⚠️ Hashes this object based on its instance ID.
465 ///
466 /// # Panics
467 /// When `self` is dead.
468 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
469 self.obj.hash(state);
470 }
471}
472
473impl<T, D> ops::Deref for DynGd<T, D>
474where
475 T: GodotClass,
476 D: ?Sized + 'static,
477{
478 type Target = Gd<T>;
479
480 fn deref(&self) -> &Self::Target {
481 &self.obj
482 }
483}
484
485impl<T, D> ops::DerefMut for DynGd<T, D>
486where
487 T: GodotClass,
488 D: ?Sized + 'static,
489{
490 fn deref_mut(&mut self) -> &mut Self::Target {
491 &mut self.obj
492 }
493}
494
495impl<T, D> fmt::Debug for DynGd<T, D>
496where
497 T: GodotClass,
498 D: ?Sized,
499{
500 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
501 let trt = sys::short_type_name::<D>();
502 crate::classes::debug_string_with_trait::<T>(self, f, "DynGd", &trt)
503 }
504}
505
506impl<T, D> fmt::Display for DynGd<T, D>
507where
508 T: GodotClass,
509 D: ?Sized,
510{
511 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
512 crate::classes::display_string(self, f)
513 }
514}
515
516// ----------------------------------------------------------------------------------------------------------------------------------------------
517// Type erasure
518
519trait ErasedGd<D>
520where
521 D: ?Sized + 'static,
522{
523 fn dyn_bind(&self) -> DynGdRef<'_, D>;
524 fn dyn_bind_mut(&mut self) -> DynGdMut<'_, D>;
525
526 fn clone_box(&self) -> Box<dyn ErasedGd<D>>;
527}
528
529impl<T, D> ErasedGd<D> for Gd<T>
530where
531 T: AsDyn<D> + Bounds<Declarer = bounds::DeclUser>,
532 D: ?Sized + 'static,
533{
534 fn dyn_bind(&self) -> DynGdRef<'_, D> {
535 DynGdRef::from_guard::<T>(Gd::bind(self))
536 }
537
538 fn dyn_bind_mut(&mut self) -> DynGdMut<'_, D> {
539 DynGdMut::from_guard::<T>(Gd::bind_mut(self))
540 }
541
542 fn clone_box(&self) -> Box<dyn ErasedGd<D>> {
543 Box::new(Gd::clone(self))
544 }
545}
546
547// ----------------------------------------------------------------------------------------------------------------------------------------------
548// Integration with Godot traits -- most are directly delegated to Gd<T>.
549
550impl<T, D> GodotConvert for DynGd<T, D>
551where
552 T: GodotClass,
553 D: ?Sized,
554{
555 type Via = Gd<T>;
556}
557
558impl<T, D> ToGodot for DynGd<T, D>
559where
560 T: GodotClass,
561 D: ?Sized,
562{
563 // Delegate to Gd<T> passing strategy.
564 type Pass = <Gd<T> as ToGodot>::Pass;
565
566 fn to_godot(&self) -> &Self::Via {
567 self.obj.to_godot()
568 }
569
570 fn to_variant(&self) -> Variant {
571 self.obj.to_variant()
572 }
573}
574
575impl<T, D> FromGodot for DynGd<T, D>
576where
577 T: GodotClass,
578 D: ?Sized + 'static,
579{
580 fn try_from_godot(via: Self::Via) -> Result<Self, ConvertError> {
581 match try_dynify_object(via) {
582 Ok(dyn_gd) => Ok(dyn_gd),
583 Err((from_godot_err, obj)) => Err(from_godot_err.into_error(obj)),
584 }
585 }
586}
587
588/*
589// See `impl AsArg for Gd<T>` for why this isn't yet implemented.
590impl<'r, T, TBase, D> meta::AsArg<DynGd<TBase, D>> for &'r DynGd<T, D>
591where
592 T: Inherits<TBase>,
593 TBase: GodotClass,
594 D: ?Sized + 'static,
595{
596 fn into_arg<'arg>(self) -> meta::CowArg<'arg, DynGd<TBase, D>>
597 where
598 'r: 'arg,
599 {
600 meta::CowArg::Owned(self.clone().upcast::<TBase>())
601 }
602}
603*/
604
605impl<T, D> meta::ArrayElement for DynGd<T, D>
606where
607 T: GodotClass,
608 D: ?Sized + 'static,
609{
610 fn element_type_string() -> String {
611 let hint_string = get_dyn_property_hint_string::<T, D>();
612 object_export_element_type_string::<T>(hint_string)
613 }
614}
615
616impl<T, D> meta::ArrayElement for Option<DynGd<T, D>>
617where
618 T: GodotClass,
619 D: ?Sized + 'static,
620{
621 fn element_type_string() -> String {
622 DynGd::<T, D>::element_type_string()
623 }
624}
625
626impl<T, D> Var for DynGd<T, D>
627where
628 T: GodotClass,
629 D: ?Sized + 'static,
630{
631 fn get_property(&self) -> Self::Via {
632 self.obj.get_property()
633 }
634
635 fn set_property(&mut self, value: Self::Via) {
636 // `set_property` can't be delegated to Gd<T>, since we have to set `erased_obj` as well.
637 *self = <Self as FromGodot>::from_godot(value);
638 }
639}
640
641/// See [`DynGd` Exporting](struct.DynGd.html#exporting) section.
642impl<T, D> Export for Option<DynGd<T, D>>
643where
644 T: GodotClass + Bounds<Exportable = bounds::Yes>,
645 D: ?Sized + 'static,
646{
647 fn export_hint() -> PropertyHintInfo {
648 PropertyHintInfo::export_dyn_gd::<T, D>()
649 }
650
651 #[doc(hidden)]
652 fn as_node_class() -> Option<ClassId> {
653 PropertyHintInfo::object_as_node_class::<T>()
654 }
655}
656
657impl<T, D> Default for OnEditor<DynGd<T, D>>
658where
659 T: GodotClass,
660 D: ?Sized + 'static,
661{
662 fn default() -> Self {
663 OnEditor::gd_invalid()
664 }
665}
666
667impl<T, D> GodotConvert for OnEditor<DynGd<T, D>>
668where
669 T: GodotClass,
670 D: ?Sized + 'static,
671{
672 type Via = Option<<DynGd<T, D> as GodotConvert>::Via>;
673}
674
675impl<T, D> Var for OnEditor<DynGd<T, D>>
676where
677 T: GodotClass,
678 D: ?Sized + 'static,
679{
680 fn get_property(&self) -> Self::Via {
681 Self::get_property_inner(self)
682 }
683
684 fn set_property(&mut self, value: Self::Via) {
685 // `set_property` can't be delegated to Gd<T>, since we have to set `erased_obj` as well.
686 Self::set_property_inner(self, value)
687 }
688}
689
690/// See [`DynGd` Exporting](struct.DynGd.html#exporting) section.
691impl<T, D> Export for OnEditor<DynGd<T, D>>
692where
693 Self: Var,
694 T: GodotClass + Bounds<Exportable = bounds::Yes>,
695 D: ?Sized + 'static,
696{
697 fn export_hint() -> PropertyHintInfo {
698 PropertyHintInfo::export_dyn_gd::<T, D>()
699 }
700
701 #[doc(hidden)]
702 fn as_node_class() -> Option<ClassId> {
703 PropertyHintInfo::object_as_node_class::<T>()
704 }
705}