Skip to content

Commit 751451a

Browse files
bors[bot]chitoyuu
andauthored
Merge #1034
1034: Implement support for flexible self types r=chitoyuu a=chitoyuu `Instance` and `TInstance` can now be used as self types where applicable. Additionally, `Arc` is supported when `ArcData` is used as the user-data wrapper. The `self` type can be provided through the standard `arbitrary_self_types` syntax, or a `#[self]` attribute on the argument when unavailable. This is technically a breaking change because all `UserData` errors are now required to implement `std::error::Error`, although the possibility of actual breakage should be pretty low -- the wrapper types we ship should be powerful enough to cover most if not all valid use cases. Close #974 Co-authored-by: Chitose Yuuzaki <[email protected]>
2 parents 11466c8 + 726a5a5 commit 751451a

File tree

30 files changed

+363
-104
lines changed

30 files changed

+363
-104
lines changed

.github/workflows/full-ci.yml

+7-7
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ jobs:
130130
- rust: { toolchain: 'nightly' }
131131
testflags: '-- --skip ui_tests'
132132
- os: { id: ubuntu-latest, name: linux }
133-
rust: { toolchain: '1.63', postfix: ' (msrv 1.63)' }
133+
rust: { toolchain: '1.67', postfix: ' (msrv 1.67)' }
134134
testflags: '-- --skip ui_tests'
135135
- os: { id: ubuntu-latest, name: linux }
136136
rust: { toolchain: 'stable', postfix: ' (minimal-deps)', special: 'minimal-deps' }
@@ -298,16 +298,16 @@ jobs:
298298
godot: "3.5.1-stable"
299299
postfix: ' (nightly, inventory)'
300300
build_args: '--features inventory'
301-
- rust: '1.63'
301+
- rust: '1.67'
302302
godot: "3.5.1-stable"
303-
postfix: ' (msrv 1.63)'
304-
- rust: '1.63'
303+
postfix: ' (msrv 1.67)'
304+
- rust: '1.67'
305305
godot: "3.5.1-stable"
306-
postfix: ' (msrv 1.63, ptrcall)'
306+
postfix: ' (msrv 1.67, ptrcall)'
307307
build_args: '--features ptrcall'
308-
- rust: '1.63'
308+
- rust: '1.67'
309309
godot: "3.5.1-stable"
310-
postfix: ' (msrv 1.63, inventory)'
310+
postfix: ' (msrv 1.67, inventory)'
311311
build_args: '--features inventory'
312312

313313
# Test with oldest supported engine version

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
The bindings cover most of the exposed API of Godot 3.5, and are being used on a number of projects in development, but we still expect non-trivial breaking changes in the API in the coming releases. godot-rust adheres to [Cargo's semantic versioning](https://doc.rust-lang.org/cargo/reference/semver.html).
1919

20-
Minimum supported Rust version (MSRV) is **1.63**. We use the Rust 2021 Edition.
20+
Minimum supported Rust version (MSRV) is **1.67**. We use the Rust 2021 Edition.
2121

2222

2323
## Engine compatibility

bindings-generator/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ license = "MIT"
99
version = "0.11.3"
1010
workspace = ".."
1111
edition = "2021"
12-
rust-version = "1.63"
12+
rust-version = "1.67"
1313

1414
[features]
1515
debug = []

examples/builder-export/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "builder-export"
33
version = "0.1.0"
44
authors = ["The godot-rust developers"]
55
edition = "2021"
6-
rust-version = "1.63"
6+
rust-version = "1.67"
77
license = "MIT"
88
publish = false
99

examples/dodge-the-creeps/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ version = "0.1.0"
44
authors = ["The godot-rust developers"]
55
publish = false
66
edition = "2021"
7-
rust-version = "1.63"
7+
rust-version = "1.67"
88
license = "MIT"
99

1010
[lib]

examples/godot_tps_controller_port/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ version = "0.1.0"
44
edition = "2021"
55
authors = ["The godot-rust developers"]
66
publish = false
7-
rust-version = "1.63"
7+
rust-version = "1.67"
88
license = "MIT"
99

1010
[dependencies]

examples/hello-world/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ version = "0.1.0"
44
authors = ["The godot-rust developers"]
55
publish = false
66
edition = "2021"
7-
rust-version = "1.63"
7+
rust-version = "1.67"
88
license = "MIT"
99

1010
[lib]

examples/native-plugin/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "native-plugin"
33
version = "0.1.0"
44
authors = ["The godot-rust developers"]
55
edition = "2021"
6-
rust-version = "1.63"
6+
rust-version = "1.67"
77
license = "MIT"
88
publish = false
99

examples/property-export/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "property-export"
33
version = "0.1.0"
44
authors = ["The godot-rust developers"]
55
edition = "2021"
6-
rust-version = "1.63"
6+
rust-version = "1.67"
77
license = "MIT"
88
publish = false
99

examples/resource/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ version = "0.1.0"
44
authors = ["The godot-rust developers"]
55
publish = false
66
edition = "2021"
7-
rust-version = "1.63"
7+
rust-version = "1.67"
88
license = "MIT"
99

1010
[lib]

examples/rpc/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ version = "0.1.0"
44
authors = ["The godot-rust developers"]
55
publish = false
66
edition = "2021"
7-
rust-version = "1.63"
7+
rust-version = "1.67"
88
license = "MIT"
99

1010
[lib]

examples/scene-create/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ version = "0.1.0"
44
authors = ["The godot-rust developers"]
55
publish = false
66
edition = "2021"
7-
rust-version = "1.63"
7+
rust-version = "1.67"
88
license = "MIT"
99

1010
[lib]

examples/signals/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "signals"
33
version = "0.1.0"
44
authors = ["The godot-rust developers"]
55
edition = "2021"
6-
rust-version = "1.63"
6+
rust-version = "1.67"
77
license = "MIT"
88
publish = false
99

examples/spinning-cube/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "spinning-cube"
33
version = "0.1.0"
44
authors = ["The godot-rust developers"]
55
edition = "2021"
6-
rust-version = "1.63"
6+
rust-version = "1.67"
77
license = "MIT"
88
publish = false
99

gdnative-async/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ version = "0.11.3"
99
license = "MIT"
1010
workspace = ".."
1111
edition = "2021"
12-
rust-version = "1.63"
12+
rust-version = "1.67"
1313

1414
[features]
1515

gdnative-bindings/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ version = "0.11.3"
99
license = "MIT"
1010
workspace = ".."
1111
edition = "2021"
12-
rust-version = "1.63"
12+
rust-version = "1.67"
1313

1414
[features]
1515
formatted = []

gdnative-core/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ version = "0.11.3"
99
license = "MIT"
1010
workspace = ".."
1111
edition = "2021"
12-
rust-version = "1.63"
12+
rust-version = "1.67"
1313

1414
[features]
1515
default = []

gdnative-core/src/export/user_data.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ pub unsafe trait UserData: Sized + Clone {
121121

122122
/// Trait for wrappers that can be mapped immutably.
123123
pub trait Map: UserData {
124-
type Err: Debug;
124+
type Err: std::error::Error;
125125

126126
/// Maps a `&T` to `U`. Called for methods that take `&self`.
127127
///
@@ -134,7 +134,7 @@ pub trait Map: UserData {
134134

135135
/// Trait for wrappers that can be mapped mutably.
136136
pub trait MapMut: UserData {
137-
type Err: Debug;
137+
type Err: std::error::Error;
138138

139139
/// Maps a `&mut T` to `U`. Called for methods that take `&mut self`.
140140
///
@@ -147,7 +147,7 @@ pub trait MapMut: UserData {
147147

148148
/// Trait for wrappers that can be mapped once.
149149
pub trait MapOwned: UserData {
150-
type Err: Debug;
150+
type Err: std::error::Error;
151151

152152
/// Maps a `T` to `U`. Called for methods that take `self`. This method may fail with
153153
/// an error if it is called more than once on the same object.
@@ -168,10 +168,11 @@ pub type DefaultUserData<T> = LocalCellData<T>;
168168
#[allow(clippy::exhaustive_enums)] // explicitly uninhabited
169169
pub enum Infallible {}
170170

171+
impl std::error::Error for Infallible {}
171172
impl std::fmt::Display for Infallible {
172173
#[inline]
173-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174-
write!(f, "operation that can't fail just failed")
174+
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175+
unreachable!("uninhabited enum")
175176
}
176177
}
177178

gdnative-core/src/object/instance.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::fmt::Debug;
12
use std::ptr::NonNull;
23

34
use crate::core_types::{
@@ -13,6 +14,9 @@ use crate::object::ownership::{NonUniqueOwnership, Ownership, Shared, ThreadLoca
1314
use crate::object::{GodotObject, Instanciable, QueueFree, RawObject, Ref, TRef};
1415
use crate::private::{get_api, ReferenceCountedClassPlaceholder};
1516

17+
mod receiver;
18+
19+
pub use receiver::Receiver;
1620
/// A persistent reference to a GodotObject with a rust NativeClass attached.
1721
///
1822
/// `Instance`s can be worked on directly using `map` and `map_mut` if the base object is
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
use std::fmt::{Debug, Display};
2+
use std::sync::Arc;
3+
4+
use crate::export::user_data::{ArcData, Map, MapMut, MapOwned};
5+
use crate::export::NativeClass;
6+
use crate::object::ownership::Shared;
7+
8+
use super::{Instance, TInstance};
9+
10+
/// Trait for types that can be used as the `self` or `#[self]` argument (receiver) for methods
11+
/// exported through the `#[methods]` attribute macro. This trait has no public interface, and
12+
/// is not intended to be implemented by users.
13+
///
14+
/// Notably, this is implemented for [`Instance`] and [`TInstance`] along with the usual `self`
15+
/// reference types. For types using [`ArcData`] as the wrapper specifically, [`Arc<C>`] is also
16+
/// allowed.
17+
///
18+
/// The trait is unsealed for technical coherence issues, but is not intended to be implemented
19+
/// by users. Changes to the definition of this trait are not considered breaking changes under
20+
/// semver.
21+
pub trait Receiver<C: NativeClass>: Sized {
22+
#[doc(hidden)]
23+
type This<'a>;
24+
#[doc(hidden)]
25+
type Err: std::error::Error;
26+
27+
#[doc(hidden)]
28+
fn with_instance<F, R>(instance: TInstance<'_, C, Shared>, f: F) -> Result<R, Self::Err>
29+
where
30+
F: for<'a> FnOnce(Self::This<'a>) -> R;
31+
}
32+
33+
/// Error type indicating that an operation can't fail.
34+
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
35+
#[allow(clippy::exhaustive_enums)] // explicitly uninhabited
36+
pub enum Infallible {}
37+
38+
impl std::error::Error for Infallible {}
39+
impl Display for Infallible {
40+
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41+
unreachable!("uninhabited enum")
42+
}
43+
}
44+
45+
impl<'r, C: NativeClass> Receiver<C> for TInstance<'r, C, Shared> {
46+
type This<'a> = TInstance<'a, C, Shared>;
47+
type Err = Infallible;
48+
49+
#[inline]
50+
fn with_instance<F, R>(instance: TInstance<'_, C, Shared>, f: F) -> Result<R, Self::Err>
51+
where
52+
F: for<'a> FnOnce(Self::This<'a>) -> R,
53+
{
54+
Ok(f(instance))
55+
}
56+
}
57+
58+
impl<C: NativeClass> Receiver<C> for Instance<C, Shared> {
59+
type This<'a> = Instance<C, Shared>;
60+
type Err = Infallible;
61+
62+
#[inline]
63+
fn with_instance<F, R>(instance: TInstance<'_, C, Shared>, f: F) -> Result<R, Self::Err>
64+
where
65+
F: for<'a> FnOnce(Self::This<'a>) -> R,
66+
{
67+
Ok(f(instance.claim()))
68+
}
69+
}
70+
71+
impl<'r, C: NativeClass> Receiver<C> for &'r C
72+
where
73+
C::UserData: Map,
74+
{
75+
type This<'a> = &'a C;
76+
type Err = <C::UserData as Map>::Err;
77+
78+
#[inline]
79+
fn with_instance<F, R>(instance: TInstance<'_, C, Shared>, f: F) -> Result<R, Self::Err>
80+
where
81+
F: for<'a> FnOnce(Self::This<'a>) -> R,
82+
{
83+
instance.map(|this, _| f(this))
84+
}
85+
}
86+
87+
impl<'r, C: NativeClass> Receiver<C> for &'r mut C
88+
where
89+
C::UserData: MapMut,
90+
{
91+
type This<'a> = &'a mut C;
92+
type Err = <C::UserData as MapMut>::Err;
93+
94+
#[inline]
95+
fn with_instance<F, R>(instance: TInstance<'_, C, Shared>, f: F) -> Result<R, Self::Err>
96+
where
97+
F: for<'a> FnOnce(Self::This<'a>) -> R,
98+
{
99+
instance.map_mut(|this, _| f(this))
100+
}
101+
}
102+
103+
impl<C: NativeClass> Receiver<C> for C
104+
where
105+
C::UserData: MapOwned,
106+
{
107+
type This<'a> = C;
108+
type Err = <C::UserData as MapOwned>::Err;
109+
110+
#[inline]
111+
fn with_instance<F, R>(instance: TInstance<'_, C, Shared>, f: F) -> Result<R, Self::Err>
112+
where
113+
F: for<'a> FnOnce(Self::This<'a>) -> R,
114+
{
115+
instance.map_owned(|this, _| f(this))
116+
}
117+
}
118+
119+
impl<C> Receiver<C> for Arc<C>
120+
where
121+
C: NativeClass<UserData = ArcData<C>>,
122+
{
123+
type This<'a> = Arc<C>;
124+
type Err = Infallible;
125+
126+
#[inline]
127+
fn with_instance<F, R>(instance: TInstance<'_, C, Shared>, f: F) -> Result<R, Self::Err>
128+
where
129+
F: for<'a> FnOnce(Self::This<'a>) -> R,
130+
{
131+
let (_, script) = instance.claim().decouple();
132+
Ok(f(script.into_inner()))
133+
}
134+
}

gdnative-derive/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ version = "0.11.3"
99
license = "MIT"
1010
workspace = ".."
1111
edition = "2021"
12-
rust-version = "1.63"
12+
rust-version = "1.67"
1313

1414
[lib]
1515
proc-macro = true

0 commit comments

Comments
 (0)