@@ -7,6 +7,7 @@ extern crate quote;
7
7
8
8
use proc_macro:: TokenStream ;
9
9
use proc_macro2:: TokenStream as TokenStream2 ;
10
+ use quote:: ToTokens ;
10
11
use syn:: { AttributeArgs , DeriveInput , ItemFn , ItemImpl } ;
11
12
12
13
mod extend_bounds;
@@ -18,7 +19,12 @@ mod variant;
18
19
19
20
/// Collects method signatures of all functions in a `NativeClass` that have the `#[method]` attribute and registers them with Godot.
20
21
///
21
- /// For example, in the following class
22
+ /// **Important**: Only one `impl` block per struct may be attributed with `#[methods]`.
23
+ ///
24
+ /// For more context, please refer to [gdnative::derive::NativeClass](NativeClass).
25
+ ///
26
+ /// ## Example
27
+ ///
22
28
/// ```
23
29
/// use gdnative::prelude::*;
24
30
///
@@ -36,34 +42,6 @@ mod variant;
36
42
/// }
37
43
///
38
44
/// ```
39
- /// Will expand to
40
- /// ```
41
- /// use gdnative::prelude::*;
42
- /// struct Foo {}
43
- /// impl NativeClass for Foo {
44
- /// type Base = gdnative::api::Reference;
45
- /// type UserData = gdnative::export::user_data::LocalCellData<Self>;
46
- /// }
47
- /// impl gdnative::export::StaticallyNamed for Foo {
48
- /// const CLASS_NAME: &'static str = "Foo";
49
- /// }
50
- /// impl gdnative::export::NativeClassMethods for Foo {
51
- /// fn nativeclass_register(builder: &ClassBuilder<Self>) {
52
- /// use gdnative::export::*;
53
- /// builder.method("foo", gdnative::export::godot_wrap_method!(Foo, false, fn foo(&self, #[base] _base: &Reference, bar: i64) -> i64))
54
- /// .with_rpc_mode(RpcMode::Disabled)
55
- /// .done_stateless();
56
- /// }
57
- /// }
58
- /// impl Foo {
59
- /// fn foo(&self, _owner: &Reference, bar: i64) -> i64 {
60
- /// bar
61
- /// }
62
- /// }
63
- /// ```
64
- /// **Important**: Only one `impl` block per struct may be attributed with `#[methods]`.
65
- ///
66
- /// For more context, please refer to [gdnative::derive::NativeClass](NativeClass).
67
45
#[ proc_macro_attribute]
68
46
pub fn methods ( meta : TokenStream , input : TokenStream ) -> TokenStream {
69
47
if syn:: parse :: < syn:: parse:: Nothing > ( meta. clone ( ) ) . is_err ( ) {
@@ -237,18 +215,19 @@ pub fn profiled(meta: TokenStream, input: TokenStream) -> TokenStream {
237
215
///
238
216
/// **Important**: This needs to be added to one and only one `impl` block for a given `NativeClass`.
239
217
///
240
- /// For additional details about how `#[methods]` expands, please refer to [gdnative::methods](macro@methods)
241
- ///
242
218
/// ### `#[method]`
243
219
/// Registers the attributed function signature to be used by Godot.
244
220
///
245
221
/// This attribute was formerly called `#[export]`, but is not directly related to the concept of
246
222
/// [exporting](https://docs.godotengine.org/en/stable/tutorials/export/exporting_basics.html) in GDScript.
247
223
///
248
224
/// A valid function signature must have:
249
- /// - `&self` or `&mut self` as its first parameter
250
- /// - Optionally, `&T` or `TRef<T>` where T refers to the type declared in `#[inherit(T)]` attribute as it's second parameter;
251
- /// this is typically called the _base_. The parameter must be attributed with `#[base]`.
225
+ /// - `self`, `&self` or `&mut self` as its first parameter, if applicable.
226
+ /// - Up of one of each of the following special arguments, in any order, denoted by the attributes:
227
+ /// - `#[base]` - A reference to the base/owner object. This may be `&T` or `TRef<T>`m where `T` refers to
228
+ /// the type declared in `#[inherit(T)]` attribute for the `NativeClass` type.
229
+ /// - `#[async_ctx]` - The [async context](gdnative::tasks::Context), for async methods. See the `async` argument
230
+ /// below.
252
231
/// - Any number of required parameters, which must have the type `Variant` or must implement the `FromVariant` trait.
253
232
/// `FromVariant` is implemented for most common types.
254
233
/// - Any number of optional parameters annotated with `#[opt]`. Same rules as for required parameters apply.
@@ -257,6 +236,10 @@ pub fn profiled(meta: TokenStream, input: TokenStream) -> TokenStream {
257
236
/// or be a `Variant` type.
258
237
///
259
238
/// ```ignore
239
+ /// // Associated function
240
+ /// #[method]
241
+ /// fn foo();
242
+ ///
260
243
/// // No access to base parameter
261
244
/// #[method]
262
245
/// fn foo(&self);
@@ -268,6 +251,20 @@ pub fn profiled(meta: TokenStream, input: TokenStream) -> TokenStream {
268
251
/// // Access base parameter as TRef<T>
269
252
/// #[method]
270
253
/// fn foo(&self, #[base] base: TRef<Reference>);
254
+ ///
255
+ /// // Access only the async context. Both variations are valid.
256
+ /// #[method]
257
+ /// async fn foo(#[async_ctx] ctx: Arc<Context>);
258
+ /// #[method(async)]
259
+ /// fn foo(#[async_ctx] ctx: Arc<Context>) -> impl Future<Output = ()> + 'static;
260
+ ///
261
+ /// // Access the base parameter as TRef<T>, and the async context. Both variations are valid.
262
+ /// // Note the absence of `async fn`s here: this is due to a current limitation in Rust's lifetime elision rules.
263
+ /// // See the `async` attribute argument down below for more details.
264
+ /// #[method(async)]
265
+ /// fn foo(&self, #[base] base: TRef<Reference>, #[async_ctx] ctx: Arc<Context>) -> impl Future<Output = ()> + 'static;
266
+ /// #[method(async)]
267
+ /// fn foo(&self, #[async_ctx] ctx: Arc<Context>, #[base] base: TRef<Reference>) -> impl Future<Output = ()> + 'static;
271
268
/// ```
272
269
///
273
270
/// **Note**: Marking a function with `#[method]` does not have any effect unless inside an `impl` block that has the `#[methods]` attribute.
@@ -307,6 +304,29 @@ pub fn profiled(meta: TokenStream, input: TokenStream) -> TokenStream {
307
304
/// }
308
305
/// ```
309
306
///
307
+ /// - `async`
308
+ ///
309
+ /// Marks the function as async. This is used for functions that aren't `async` themselves, but return `Future`s instead.
310
+ /// This is especially useful for working around Rust's lifetime elision rules, which put the lifetime of `&self` into the
311
+ /// return value for `async fn`s. The `impl Future` syntax instead allows one to explicitly specify a `'static` lifetime,
312
+ /// as required by the async runtime:
313
+ ///
314
+ /// ```ignore
315
+ /// // This will NOT compile: Rust assumes that any futures returned by an `async fn` may only live as long as each of its
316
+ /// // arguments, and there is no way to tell it otherwise. As a result, it will emit some cryptic complaints about lifetime.
317
+ /// #[method]
318
+ /// async fn answer(&self) -> i32 {
319
+ /// 42
320
+ /// }
321
+ ///
322
+ /// // This, however, compiles, thanks to the explicit `'static` lifetime in the return signature.
323
+ /// #[method(async)]
324
+ /// fn answer(&self) -> impl Future<Output = i32> + 'static {
325
+ /// async { 42 }
326
+ /// }
327
+ ///
328
+ /// ```
329
+ ///
310
330
///
311
331
/// #### `Node` virtual functions
312
332
///
@@ -525,7 +545,31 @@ fn crate_gdnative_core() -> proc_macro2::TokenStream {
525
545
proc_macro_crate:: FoundCrate :: Itself => quote ! ( crate ) ,
526
546
proc_macro_crate:: FoundCrate :: Name ( name) => {
527
547
let ident = proc_macro2:: Ident :: new ( & name, proc_macro2:: Span :: call_site ( ) ) ;
528
- quote ! ( #ident )
548
+ ident. to_token_stream ( )
549
+ }
550
+ }
551
+ }
552
+
553
+ /// Returns the (possibly renamed or imported as `gdnative`) identifier of the `gdnative_async` crate,
554
+ /// if found.
555
+ fn crate_gdnative_async ( ) -> proc_macro2:: TokenStream {
556
+ if let Ok ( found_crate) = proc_macro_crate:: crate_name ( "gdnative-async" ) {
557
+ return match found_crate {
558
+ proc_macro_crate:: FoundCrate :: Itself => quote ! ( crate ) ,
559
+ proc_macro_crate:: FoundCrate :: Name ( name) => {
560
+ let ident = proc_macro2:: Ident :: new ( & name, proc_macro2:: Span :: call_site ( ) ) ;
561
+ ident. to_token_stream ( )
562
+ }
563
+ } ;
564
+ }
565
+
566
+ let found_crate = proc_macro_crate:: crate_name ( "gdnative" ) . expect ( "crate not found" ) ;
567
+
568
+ match found_crate {
569
+ proc_macro_crate:: FoundCrate :: Itself => quote ! ( crate :: tasks) ,
570
+ proc_macro_crate:: FoundCrate :: Name ( name) => {
571
+ let ident = proc_macro2:: Ident :: new ( & name, proc_macro2:: Span :: call_site ( ) ) ;
572
+ quote ! ( #ident:: tasks )
529
573
}
530
574
}
531
575
}
0 commit comments