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