godot_core/meta/uniform_object_deref.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::ops::{Deref, DerefMut};
9
10use crate::obj::bounds::{DeclEngine, DeclUser};
11use crate::obj::{Gd, GdMut, GdRef, GodotClass, WithBaseField};
12
13/// Unifies dereferencing of user and engine classes, as `&T`/`&mut T` and `Gd<T>`.
14///
15/// This is mainly used by the `connect_*` functions of [`TypedSignal`](crate::registry::signal::TypedSignal).
16///
17/// # Motivation
18/// Although both user and engine classes are often wrapped in a `Gd<T>`, dereferencing them is done differently depending
19/// on whether they are made by the user or engine:
20/// - `Gd<EngineClass>` can be deref-ed directly into `&EngineClass` and `&mut EngineClass`.
21/// - `Gd<UserClass>` must first go through [`bind()`](Gd::bind)/[`bind_mut()`](Gd::bind_mut), which can finally
22/// be deref-ed into `&UserClass` and `&mut UserClass`, respectively.
23///
24/// Without this trait, there's no clear/generic way of writing functions that can accept both user and engine classes,
25/// but need to deref said classes in some way.
26///
27/// [`UniformObjectDeref`](Self) solves this by explicitly handling each category in a different way, but still resulting
28/// in a variable that can be deref-ed into `&T`/`&mut T`.
29///
30/// # Generic param `Declarer`
31/// Rustc [does not acknowledge associated type bounds when checking for overlapping impls](https://github.com/rust-lang/rust/issues/20400),
32/// this parameter is essentially used to create 2 different traits, one for each "category" (user or engine).
33///
34/// Despite being 2 different traits, a function can accept both by simply being generic over `Declarer`:
35/// ```no_run
36/// use godot::meta::UniformObjectDeref;
37/// # use godot::prelude::*;
38///
39/// fn abstract_over_objects<Declarer, C>(obj: &Gd<C>)
40/// where
41/// C: UniformObjectDeref<Declarer>,
42/// {
43/// let ref_provider = UniformObjectDeref::object_as_ref(obj);
44/// let obj_ref: &C = & *ref_provider;
45/// // Regardless of `Declarer`, we can still deref, since the bounds on
46/// // `TargetRef`/`TargetMut` enforce that.
47/// }
48///
49/// #[derive(GodotClass)]
50/// #[class(init)]
51/// struct MyClass {
52/// _base: Base<RefCounted>
53/// }
54///
55/// fn main() {
56/// let engine_obj: Gd<RefCounted> = RefCounted::new_gd();
57/// let user_obj: Gd<MyClass> = MyClass::new_gd();
58///
59/// abstract_over_objects(&engine_obj);
60/// abstract_over_objects(&user_obj);
61/// }
62/// ```
63///
64/// # Similar traits
65/// - [`ObjectToOwned`][crate::meta::ObjectToOwned] provides conversion from `&self` or `&Gd<T>` to owned `Gd<T>`.
66//
67// The crate `https://crates.io/crates/disjoint_impls` handles this in a more user-friendly way, we should
68// consider using it if disjoint impls are going to be frequently used.
69//
70// See also Declarer::DerefTarget in the library, which has a similar but different purpose: finding the nearest engine class
71// (`&Node` for `Node`, `&Node` for `MyClass`).
72#[allow(clippy::needless_lifetimes)] // False positive.
73pub trait UniformObjectDeref<Declarer>: GodotClass {
74 // Currently, only the mut parts are used within the library; but ref might be useful too.
75 type TargetRef<'a>: Deref<Target = Self>;
76 type TargetMut<'a>: DerefMut<Target = Self>;
77
78 fn object_as_ref<'a>(gd: &'a Gd<Self>) -> Self::TargetRef<'a>;
79 fn object_as_mut<'a>(gd: &'a mut Gd<Self>) -> Self::TargetMut<'a>;
80}
81
82#[allow(clippy::needless_lifetimes)] // False positive.
83impl<T: GodotClass<Declarer = DeclEngine>> UniformObjectDeref<DeclEngine> for T {
84 type TargetRef<'a> = Gd<T>;
85 type TargetMut<'a> = Gd<T>;
86
87 fn object_as_ref<'a>(gd: &'a Gd<Self>) -> Self::TargetRef<'a> {
88 gd.clone()
89 }
90 fn object_as_mut<'a>(gd: &'a mut Gd<Self>) -> Self::TargetMut<'a> {
91 gd.clone()
92 }
93}
94
95#[allow(clippy::needless_lifetimes)] // False positive.
96impl<T: WithBaseField> UniformObjectDeref<DeclUser> for T {
97 type TargetRef<'a> = GdRef<'a, T>;
98 type TargetMut<'a> = GdMut<'a, T>;
99
100 fn object_as_ref<'a>(gd: &'a Gd<Self>) -> Self::TargetRef<'a> {
101 gd.bind()
102 }
103 fn object_as_mut<'a>(gd: &'a mut Gd<Self>) -> Self::TargetMut<'a> {
104 gd.bind_mut()
105 }
106}