Skip to content

Commit 446e3b5

Browse files
committed
Improve API docs for #[godot_api]
1 parent 67ea06f commit 446e3b5

File tree

2 files changed

+128
-21
lines changed

2 files changed

+128
-21
lines changed

godot-macros/src/lib.rs

Lines changed: 126 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,6 @@ pub fn derive_godot_class(input: TokenStream) -> TokenStream {
444444

445445
/// Proc-macro attribute to be used with `impl` blocks of [`#[derive(GodotClass)]`][GodotClass] structs.
446446
///
447-
/// See also [book chapter _Registering functions_](https://godot-rust.github.io/book/register/functions.html) and following.
448-
///
449447
/// Can be used in two ways:
450448
/// ```no_run
451449
/// # use godot::prelude::*;
@@ -462,57 +460,77 @@ pub fn derive_godot_class(input: TokenStream) -> TokenStream {
462460
/// impl INode for MyClass { /* ... */ }
463461
/// ```
464462
///
465-
/// The second case works by implementing the corresponding trait `I<Base>` for the base class of your class
463+
/// The second case works by implementing the corresponding trait `I*` for the base class of your class
466464
/// (for example `IRefCounted` or `INode3D`). Then, you can add functionality such as:
467465
/// * `init` constructors
468466
/// * lifecycle methods like `ready` or `process`
469467
/// * `on_notification` method
470468
/// * `to_string` method
471469
///
472-
/// Neither `#[godot_api]` attribute is required. For small data bundles inheriting `RefCounted`, you may be fine with
470+
/// Neither of the two `#[godot_api]` blocks is required. For small data bundles inheriting `RefCounted`, you may be fine with
473471
/// accessing properties directly from GDScript.
474472
///
475-
/// # Examples
473+
/// See also [book chapter _Registering functions_](https://godot-rust.github.io/book/register/functions.html) and following.
476474
///
477-
/// ## `RefCounted` as a base, overridden `init`
475+
/// **Table of contents**
476+
/// - [Constructors](#constructors)
477+
/// - [User-defined `init`](#user-defined-init)
478+
/// - [Generated `init`](#generated-init)
479+
/// - [Lifecycle functions](#lifecycle-functions)
480+
/// - [User-defined functions](#user-defined-functions)
481+
/// - [Associated functions and methods](#associated-functions-and-methods)
482+
/// - [Virtual methods](#virtual-methods)
483+
/// - [Constants and signals](#signals)
478484
///
479-
/// ```no_run
480-
///# use godot::prelude::*;
485+
/// # Constructors
486+
///
487+
/// Note that `init` (the Godot default constructor) can be either provided by overriding it, or generated with a `#[class(init)]` attribute
488+
/// on the struct. Classes without `init` cannot be instantiated from GDScript.
481489
///
490+
/// ## User-defined `init`
491+
///
492+
/// ```no_run
493+
/// # use godot::prelude::*;
482494
/// #[derive(GodotClass)]
483495
/// // no #[class(init)] here, since init() is overridden below.
484496
/// // #[class(base=RefCounted)] is implied if no base is specified.
485497
/// struct MyStruct;
486498
///
487499
/// #[godot_api]
488-
/// impl MyStruct {
489-
/// #[func]
490-
/// pub fn hello_world(&mut self) {
491-
/// godot_print!("Hello World!")
492-
/// }
493-
/// }
494-
///
495-
/// #[godot_api]
496500
/// impl IRefCounted for MyStruct {
497501
/// fn init(_base: Base<RefCounted>) -> Self {
498502
/// MyStruct
499503
/// }
500504
/// }
501505
/// ```
502506
///
503-
/// Note that `init` can be either provided by overriding it, or generated with a `#[class(init)]` attribute on the struct.
504-
/// Classes without `init` cannot be instantiated from GDScript.
507+
/// ## Generated `init`
505508
///
506-
/// ## `Node` as a base, generated `init`
509+
/// This initializes the `Base<T>` field, and every other field with either `Default::default()` or the value specified in `#[init(default = ...)]`.
507510
///
508511
/// ```no_run
509-
///# use godot::prelude::*;
510-
///
512+
/// # use godot::prelude::*;
511513
/// #[derive(GodotClass)]
512514
/// #[class(init, base=Node)]
513515
/// pub struct MyNode {
514516
/// base: Base<Node>,
517+
///
518+
/// #[init(default = 42)]
519+
/// some_integer: i64,
515520
/// }
521+
/// ```
522+
///
523+
///
524+
/// # Lifecycle functions
525+
///
526+
/// You can override the lifecycle functions `ready`, `process`, `physics_process` and so on, by implementing the trait corresponding to the
527+
/// base class.
528+
///
529+
/// ```no_run
530+
/// # use godot::prelude::*;
531+
/// #[derive(GodotClass)]
532+
/// #[class(init, base=Node)]
533+
/// pub struct MyNode;
516534
///
517535
/// #[godot_api]
518536
/// impl INode for MyNode {
@@ -521,6 +539,93 @@ pub fn derive_godot_class(input: TokenStream) -> TokenStream {
521539
/// }
522540
/// }
523541
/// ```
542+
///
543+
///
544+
/// # User-defined functions
545+
///
546+
/// You can use the `#[func]` attribute to declare your own functions. These are exposed to Godot and callable from GDScript.
547+
///
548+
/// ## Associated functions and methods
549+
///
550+
/// If `#[func]` functions are called from the engine, they implicitly bind the surrounding `Gd<T>` pointer: `Gd::bind()` in case of `&self`,
551+
/// `Gd::bind_mut()` in case of `&mut self`. To avoid that, use `#[func(gd_self)]`, which requires an explicit first argument of type `Gd<T>`.
552+
///
553+
/// Functions without a receiver become static functions in Godot. They can be called from GDScript using `MyStruct.static_function()`.
554+
/// If they return `Gd<Self>`, they are effectively constructors that allow taking arguments.
555+
///
556+
/// ```no_run
557+
/// # use godot::prelude::*;
558+
/// #[derive(GodotClass)]
559+
/// #[class(init)]
560+
/// struct MyStruct {
561+
/// field: i64,
562+
/// base: Base<RefCounted>,
563+
/// }
564+
///
565+
/// #[godot_api]
566+
/// impl MyStruct {
567+
/// #[func]
568+
/// pub fn hello_world(&mut self) {
569+
/// godot_print!("Hello World!")
570+
/// }
571+
///
572+
/// #[func]
573+
/// pub fn static_function(constructor_arg: i64) -> Gd<Self> {
574+
/// Gd::from_init_fn(|base| {
575+
/// MyStruct { field: constructor_arg, base }
576+
/// })
577+
/// }
578+
///
579+
/// #[func(gd_self)]
580+
/// pub fn explicit_receiver(mut this: Gd<Self>, other_arg: bool) {
581+
/// // Only bind Gd pointer if needed.
582+
/// if other_arg {
583+
/// this.bind_mut().field = 55;
584+
/// }
585+
/// }
586+
/// }
587+
/// ```
588+
///
589+
/// ## Virtual methods
590+
///
591+
/// Functions with the `#[func(virtual)]` attribute are virtual functions, meaning attached scripts can override them.
592+
///
593+
/// ```no_run
594+
/// # #[cfg(since_api = "4.3")]
595+
/// # mod conditional {
596+
/// # use godot::prelude::*;
597+
/// #[derive(GodotClass)]
598+
/// #[class(init)]
599+
/// struct MyStruct {
600+
/// // Virtual functions require base object.
601+
/// base: Base<RefCounted>,
602+
/// }
603+
///
604+
/// #[godot_api]
605+
/// impl MyStruct {
606+
/// #[func(virtual)]
607+
/// fn language(&self) -> GString {
608+
/// "Rust".into()
609+
/// }
610+
/// }
611+
/// # }
612+
/// ```
613+
///
614+
/// In GDScript:
615+
/// ```gdscript
616+
/// extends MyStruct
617+
///
618+
/// func language():
619+
/// return "GDScript"
620+
/// ```
621+
///
622+
/// Now, `obj.language()` from Rust will dynamically dispatch the call.
623+
///
624+
/// Make sure you understand the limitations in the [tutorial](https://godot-rust.github.io/book/register/virtual-functions.html).
625+
///
626+
/// # Constants and signals
627+
///
628+
/// Please refer to [the book](https://godot-rust.github.io/book/register/constants.html).
524629
#[proc_macro_attribute]
525630
pub fn godot_api(_meta: TokenStream, input: TokenStream) -> TokenStream {
526631
translate(input, class::attribute_godot_api)

godot/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@
107107
//!
108108
//! The following features can be enabled for this crate. All off them are off by default.
109109
//!
110+
//! Avoid `default-features = false` unless you know exactly what you are doing; it will disable some required internal features.
111+
//!
110112
//! * **`double-precision`**
111113
//!
112114
//! Use `f64` instead of `f32` for the floating-point type [`real`][type@builtin::real]. Requires Godot to be compiled with the

0 commit comments

Comments
 (0)