Skip to content

Commit feff365

Browse files
authored
Merge pull request #759 from lilizoey/fix/upcast-ref-wrong
Add an engine class bound to `upcast_ref`/`upcast_mut`
2 parents e93fa52 + 5e2204c commit feff365

File tree

2 files changed

+42
-6
lines changed

2 files changed

+42
-6
lines changed

godot-core/src/obj/gd.rs

+38-4
Original file line numberDiff line numberDiff line change
@@ -295,12 +295,29 @@ impl<T: GodotClass> Gd<T> {
295295
/// println!("Node name: {}", node.upcast_ref().get_name());
296296
/// }
297297
/// ```
298+
///
299+
/// Note that this cannot be used to get a reference to Rust classes, for that you should use [`Gd::bind()`]. For instance this
300+
/// will fail:
301+
/// ```compile_fail
302+
/// # use godot::prelude::*;
303+
/// #[derive(GodotClass)]
304+
/// #[class(init, base = Node)]
305+
/// struct SomeClass {}
306+
///
307+
/// #[godot_api]
308+
/// impl INode for SomeClass {
309+
/// fn ready(&mut self) {
310+
/// let other = SomeClass::new_alloc();
311+
/// let _ = other.upcast_ref::<SomeClass>();
312+
/// }
313+
/// }
314+
/// ```
298315
pub fn upcast_ref<Base>(&self) -> &Base
299316
where
300-
Base: GodotClass,
317+
Base: GodotClass + Bounds<Declarer = bounds::DeclEngine>,
301318
T: Inherits<Base>,
302319
{
303-
// SAFETY: valid upcast enforced by Inherits bound.
320+
// SAFETY: `Base` is guaranteed to be an engine base class of `T` because of the generic bounds.
304321
unsafe { self.raw.as_upcast_ref::<Base>() }
305322
}
306323

@@ -317,12 +334,29 @@ impl<T: GodotClass> Gd<T> {
317334
/// node.upcast_mut().set_name(name.into());
318335
/// }
319336
/// ```
337+
///
338+
/// Note that this cannot be used to get a mutable reference to Rust classes, for that you should use [`Gd::bind_mut()`]. For instance this
339+
/// will fail:
340+
/// ```compile_fail
341+
/// # use godot::prelude::*;
342+
/// #[derive(GodotClass)]
343+
/// #[class(init, base = Node)]
344+
/// struct SomeClass {}
345+
///
346+
/// #[godot_api]
347+
/// impl INode for SomeClass {
348+
/// fn ready(&mut self) {
349+
/// let mut other = SomeClass::new_alloc();
350+
/// let _ = other.upcast_mut::<SomeClass>();
351+
/// }
352+
/// }
353+
/// ```
320354
pub fn upcast_mut<Base>(&mut self) -> &mut Base
321355
where
322-
Base: GodotClass,
356+
Base: GodotClass + Bounds<Declarer = bounds::DeclEngine>,
323357
T: Inherits<Base>,
324358
{
325-
// SAFETY: valid upcast enforced by Inherits bound.
359+
// SAFETY: `Base` is guaranteed to be an engine base class of `T` because of the generic bounds.
326360
unsafe { self.raw.as_upcast_mut::<Base>() }
327361
}
328362

godot-core/src/obj/raw.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,8 @@ impl<T: GodotClass> RawGd<T> {
218218
/// If this `RawGd` is null. In Debug mode, sanity checks (valid upcast, ID comparisons) can also lead to panics.
219219
///
220220
/// # Safety
221-
/// It's the caller's responsibility to ensure `Base` is actually a base class of `T`.
221+
/// - `Base` must actually be a base class of `T`.
222+
/// - `Base` must be an engine class.
222223
///
223224
/// This is not done via bounds because that would infect all APIs with `Inherits<T>` and leads to cycles in `Deref`.
224225
/// Bounds should be added on user-facing safe APIs.
@@ -254,7 +255,8 @@ impl<T: GodotClass> RawGd<T> {
254255
/// If this `RawGd` is null. In Debug mode, sanity checks (valid upcast, ID comparisons) can also lead to panics.
255256
///
256257
/// # Safety
257-
/// It's the caller's responsibility to ensure `Base` is actually a base class of `T`.
258+
/// - `Base` must actually be a base class of `T`.
259+
/// - `Base` must be an engine class.
258260
///
259261
/// This is not done via bounds because that would infect all APIs with `Inherits<T>` and leads to cycles in `Deref`.
260262
/// Bounds should be added on user-facing safe APIs.

0 commit comments

Comments
 (0)