Skip to content

Commit 9de7a8e

Browse files
authored
Merge pull request #457 from godot-rust/qol/conversion-traits-doc
`To/FromGodot` has now specific impls for native structs; trait docs
2 parents 66df8f4 + 68610a3 commit 9de7a8e

File tree

10 files changed

+116
-66
lines changed

10 files changed

+116
-66
lines changed

godot-codegen/src/class_generator.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,15 +880,52 @@ fn make_native_structure(
880880

881881
let imports = util::make_imports();
882882
let fields = make_native_structure_fields(&structure.format, ctx);
883+
let doc = format!("[`ToGodot`] and [`FromGodot`] are implemented for `*mut {class_name}` and `*const {class_name}`.");
883884

884885
// mod re_export needed, because class should not appear inside the file module, and we can't re-export private struct as pub
885886
let tokens = quote! {
886887
#imports
888+
use crate::builtin::meta::{GodotConvert, FromGodot, ToGodot};
887889

890+
/// Native structure; can be passed via pointer in APIs that are not exposed to GDScript.
891+
///
892+
#[doc = #doc]
888893
#[repr(C)]
889894
pub struct #class_name {
890895
#fields
891896
}
897+
898+
impl GodotConvert for *mut #class_name {
899+
type Via = i64;
900+
}
901+
902+
impl ToGodot for *mut #class_name {
903+
fn to_godot(&self) -> Self::Via {
904+
*self as i64
905+
}
906+
}
907+
908+
impl FromGodot for *mut #class_name {
909+
fn try_from_godot(via: Self::Via) -> Option<Self> {
910+
Some(via as Self)
911+
}
912+
}
913+
914+
impl GodotConvert for *const #class_name {
915+
type Via = i64;
916+
}
917+
918+
impl ToGodot for *const #class_name {
919+
fn to_godot(&self) -> Self::Via {
920+
*self as i64
921+
}
922+
}
923+
924+
impl FromGodot for *const #class_name {
925+
fn try_from_godot(via: Self::Via) -> Option<Self> {
926+
Some(via as Self)
927+
}
928+
}
892929
};
893930
// note: TypePtr -> ObjectPtr conversion OK?
894931

godot-codegen/src/tests.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ fn test_pascal_conversion() {
3131
("JSONRPC", "JsonRpc"),
3232
("NetworkedMultiplayerENet", "NetworkedMultiplayerENet"),
3333
("ObjectID", "ObjectId"),
34+
("OpenXRAPIExtension", "OpenXrApiExtension"),
35+
("OpenXRIPBinding", "OpenXrIpBinding"),
3436
("PackedFloat32Array", "PackedFloat32Array"),
3537
("PCKPacker", "PckPacker"),
3638
("PHashTranslation", "PHashTranslation"),
@@ -77,6 +79,8 @@ fn test_snake_conversion() {
7779
("JSONRPC", "json_rpc"),
7880
("NetworkedMultiplayerENet", "networked_multiplayer_e_net"),
7981
("ObjectID", "object_id"),
82+
("OpenXRAPIExtension", "open_xr_api_extension"),
83+
("OpenXRIPBinding", "open_xr_ip_binding"),
8084
("PackedFloat32Array", "packed_float32_array"),
8185
("PCKPacker", "pck_packer"),
8286
("PHashTranslation", "p_hash_translation"),

godot-codegen/src/util.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -431,9 +431,10 @@ pub fn to_snake_case(class_name: &str) -> String {
431431
use heck::ToSnakeCase;
432432

433433
// Special cases
434-
#[allow(clippy::single_match)]
435434
match class_name {
436435
"JSONRPC" => return "json_rpc".to_string(),
436+
"OpenXRAPIExtension" => return "open_xr_api_extension".to_string(),
437+
"OpenXRIPBinding" => return "open_xr_ip_binding".to_string(),
437438
_ => {}
438439
}
439440

@@ -448,10 +449,11 @@ pub fn to_snake_case(class_name: &str) -> String {
448449
pub fn to_pascal_case(class_name: &str) -> String {
449450
use heck::ToPascalCase;
450451

451-
// Special cases
452-
#[allow(clippy::single_match)]
452+
// Special cases: reuse snake_case impl to ensure at least consistency between those 2.
453453
match class_name {
454-
"JSONRPC" => return "JsonRpc".to_string(),
454+
"JSONRPC" | "OpenXRAPIExtension" | "OpenXRIPBinding" => {
455+
return to_snake_case(class_name).to_pascal_case()
456+
}
455457
_ => {}
456458
}
457459

godot-core/src/builtin/meta/godot_compatible/impls.rs renamed to godot-core/src/builtin/meta/godot_convert/impls.rs

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
use crate::builtin::meta::{impl_godot_as_self, FromGodot, GodotConvert, GodotType, ToGodot};
88
use godot_ffi as sys;
99

10+
// The following ToGodot/FromGodot/Convert impls are auto-generated for each engine type, co-located with their definitions:
11+
// - enum
12+
// - const/mut pointer to native struct
13+
1014
// ----------------------------------------------------------------------------------------------------------------------------------------------
1115
// Option
1216

@@ -89,41 +93,6 @@ impl FromGodot for sys::VariantOperator {
8993
}
9094
}
9195

92-
// ----------------------------------------------------------------------------------------------------------------------------------------------
93-
// Pointers
94-
95-
impl<T> GodotConvert for *mut T {
96-
type Via = i64;
97-
}
98-
99-
impl<T> ToGodot for *mut T {
100-
fn to_godot(&self) -> Self::Via {
101-
*self as i64
102-
}
103-
}
104-
105-
impl<T> FromGodot for *mut T {
106-
fn try_from_godot(via: Self::Via) -> Option<Self> {
107-
Some(via as Self)
108-
}
109-
}
110-
111-
impl<T> GodotConvert for *const T {
112-
type Via = i64;
113-
}
114-
115-
impl<T> ToGodot for *const T {
116-
fn to_godot(&self) -> Self::Via {
117-
*self as i64
118-
}
119-
}
120-
121-
impl<T> FromGodot for *const T {
122-
fn try_from_godot(via: Self::Via) -> Option<Self> {
123-
Some(via as Self)
124-
}
125-
}
126-
12796
// ----------------------------------------------------------------------------------------------------------------------------------------------
12897
// Scalars
12998

@@ -239,7 +208,6 @@ impl_godot_scalar!(
239208
u8 as i64,
240209
sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT8
241210
);
242-
243211
impl_godot_scalar!(
244212
u64 as i64,
245213
sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64;
@@ -250,3 +218,25 @@ impl_godot_scalar!(
250218
sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT;
251219
lossy
252220
);
221+
222+
// ----------------------------------------------------------------------------------------------------------------------------------------------
223+
// Raw pointers
224+
225+
// const void* is used in some APIs like OpenXrApiExtension::transform_from_pose().
226+
// Other impls for raw pointers are generated for native structures.
227+
228+
impl GodotConvert for *const std::ffi::c_void {
229+
type Via = i64;
230+
}
231+
232+
impl ToGodot for *const std::ffi::c_void {
233+
fn to_godot(&self) -> Self::Via {
234+
*self as i64
235+
}
236+
}
237+
238+
impl FromGodot for *const std::ffi::c_void {
239+
fn try_from_godot(via: Self::Via) -> Option<Self> {
240+
Some(via as Self)
241+
}
242+
}

godot-core/src/builtin/meta/godot_compatible/mod.rs renamed to godot-core/src/builtin/meta/godot_convert/mod.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ use crate::builtin::{Variant, VariantConversionError};
1010

1111
use super::{GodotFfiVariant, GodotType};
1212

13-
/// Indicates that a type has some canonical Godot type that can represent it.
13+
/// Indicates that a type can be passed to/from Godot, either directly or through an intermediate "via" type.
1414
///
15-
/// The type specified here is what will be used to pass this type across to ffi-boundary to/from Godot.
16-
/// Generally [`ToGodot`] needs to be implemented to pass a type to Godot, and [`FromGodot`] to receive this
17-
/// type from Godot.
15+
/// The associated type `Via` specifies _how_ this type is passed across the FFI boundary to/from Godot.
16+
/// Generally [`ToGodot`] needs to be implemented to pass a type to Godot, and [`FromGodot`] to receive this type from Godot.
17+
///
18+
/// [`GodotType`] is a stronger bound than [`GodotConvert`], since it expresses that a type is _directly_ representable
19+
/// in Godot (without intermediate "via"). Every `GodotType` also implements `GodotConvert` with `Via = Self`.
1820
pub trait GodotConvert {
19-
/// The type used for ffi-passing.
21+
/// The type through which `Self` is represented in Godot.
2022
type Via: GodotType;
2123
}
2224

@@ -33,8 +35,7 @@ pub trait ToGodot: Sized + GodotConvert {
3335

3436
/// Converts this type to the Godot type.
3537
///
36-
/// This can in some cases enable some optimizations, such as avoiding reference counting for
37-
/// reference-counted values.
38+
/// This can in some cases enable minor optimizations, such as avoiding reference counting operations.
3839
fn into_godot(self) -> Self::Via {
3940
self.to_godot()
4041
}

godot-core/src/builtin/meta/mod.rs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
pub mod registration;
88

99
mod class_name;
10-
mod godot_compatible;
10+
mod godot_convert;
1111
mod return_marshal;
1212
mod signature;
1313

1414
pub use class_name::*;
15-
pub use godot_compatible::*;
15+
pub use godot_convert::*;
1616
#[doc(hidden)]
1717
pub use return_marshal::*;
1818
#[doc(hidden)]
@@ -25,7 +25,8 @@ use crate::builtin::*;
2525
use crate::engine::global;
2626
use registration::method::MethodParamOrReturnInfo;
2727

28-
/// Conversion of GodotFfi-types into/from [`Variant`].
28+
/// Conversion of [`GodotFfi`] types to/from [`Variant`].
29+
#[doc(hidden)]
2930
pub trait GodotFfiVariant: Sized + GodotFfi {
3031
fn ffi_to_variant(&self) -> Variant;
3132
fn ffi_from_variant(variant: &Variant) -> Result<Self, VariantConversionError>;
@@ -98,38 +99,48 @@ mod sealed {
9899
}
99100
}
100101

101-
/// Types that can represent some Godot type.
102-
///
103-
/// This trait cannot be implemented for custom user types, for that you should see [`GodotConvert`]
104-
/// instead. A type implements `GodotType` when it can directly represent some primitive type exposed by
105-
/// Godot. For instance, [`i64`] implements `GodotType`, since it can be directly represented by Godot's
106-
/// `int` type. But [`VariantType`] does not implement `GodotType`. Since while it is an enum Godot uses, we
107-
/// have no native way to indicate to Godot that a value should be one of the variants of `VariantType`.
102+
/// Type that is directly representable in the engine.
108103
///
109-
/// Unlike [`GodotFfi`], types implementing this trait don't need to fully represent its corresponding Godot
110-
/// type. For instance [`i32`] does not implement [`GodotFfi`] because it cannot represent all values of
111-
/// Godot's `int` type, however it does implement `GodotType` because we can set the metadata of values with
112-
/// this type to indicate that they are 32 bits large.
104+
/// This trait cannot be implemented for custom user types; for those, [`GodotConvert`] exists instead.
105+
/// A type implements `GodotType` when Godot has a direct, native representation for it. For instance:
106+
/// - [`i64`] implements `GodotType`, since it can be directly represented by Godot's `int` type.
107+
/// - But [`VariantType`] does not implement `GodotType`. While it is an enum Godot uses, we have no native way to indicate
108+
/// to Godot that a value should be one of the variants of `VariantType`.
109+
//
110+
// Unlike `GodotFfi`, types implementing this trait don't need to fully represent its corresponding Godot
111+
// type. For instance [`i32`] does not implement `GodotFfi` because it cannot represent all values of
112+
// Godot's `int` type, however it does implement `GodotType` because we can set the metadata of values with
113+
// this type to indicate that they are 32 bits large.
113114
pub trait GodotType: GodotConvert<Via = Self> + ToGodot + FromGodot + sealed::Sealed {
115+
#[doc(hidden)]
114116
type Ffi: GodotFfiVariant;
115117

118+
#[doc(hidden)]
116119
fn to_ffi(&self) -> Self::Ffi;
120+
121+
#[doc(hidden)]
117122
fn into_ffi(self) -> Self::Ffi;
123+
124+
#[doc(hidden)]
118125
fn try_from_ffi(ffi: Self::Ffi) -> Option<Self>;
119126

127+
#[doc(hidden)]
120128
fn from_ffi(ffi: Self::Ffi) -> Self {
121129
Self::try_from_ffi(ffi).unwrap()
122130
}
123131

132+
#[doc(hidden)]
124133
fn param_metadata() -> sys::GDExtensionClassMethodArgumentMetadata {
125134
Self::Ffi::default_param_metadata()
126135
}
127136

137+
#[doc(hidden)]
128138
fn class_name() -> ClassName {
129139
// If we use `ClassName::of::<()>()` then this type shows up as `(no base)` in documentation.
130140
ClassName::none()
131141
}
132142

143+
#[doc(hidden)]
133144
fn property_info(property_name: &str) -> PropertyInfo {
134145
PropertyInfo {
135146
variant_type: Self::Ffi::variant_type(),
@@ -141,10 +152,12 @@ pub trait GodotType: GodotConvert<Via = Self> + ToGodot + FromGodot + sealed::Se
141152
}
142153
}
143154

155+
#[doc(hidden)]
144156
fn argument_info(property_name: &str) -> MethodParamOrReturnInfo {
145157
MethodParamOrReturnInfo::new(Self::property_info(property_name), Self::param_metadata())
146158
}
147159

160+
#[doc(hidden)]
148161
fn return_info() -> Option<MethodParamOrReturnInfo> {
149162
Some(MethodParamOrReturnInfo::new(
150163
Self::property_info(""),

godot-core/src/builtin/meta/return_marshal.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub trait PtrcallReturn {
1919

2020
// ----------------------------------------------------------------------------------------------------------------------------------------------
2121

22+
#[doc(hidden)]
2223
pub struct PtrcallReturnOptionGdT<R> {
2324
_marker: std::marker::PhantomData<R>,
2425
}
@@ -33,6 +34,7 @@ impl<T: GodotClass> PtrcallReturn for PtrcallReturnOptionGdT<Gd<T>> {
3334

3435
// ----------------------------------------------------------------------------------------------------------------------------------------------
3536

37+
#[doc(hidden)]
3638
pub struct PtrcallReturnT<R> {
3739
_marker: std::marker::PhantomData<R>,
3840
}
@@ -53,6 +55,7 @@ impl<T: FromGodot> PtrcallReturn for PtrcallReturnT<T> {
5355

5456
// ----------------------------------------------------------------------------------------------------------------------------------------------
5557

58+
#[doc(hidden)]
5659
pub enum PtrcallReturnUnit {}
5760

5861
impl PtrcallReturn for PtrcallReturnUnit {

godot-macros/src/derive/derive_godot_compatible.rs renamed to godot-macros/src/derive/derive_godot_convert.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use venial::Declaration;
1111
use crate::util::{decl_get_info, DeclInfo};
1212
use crate::ParseResult;
1313

14-
pub fn derive_godot_compatible(decl: Declaration) -> ParseResult<TokenStream> {
14+
pub fn derive_godot_convert(decl: Declaration) -> ParseResult<TokenStream> {
1515
let DeclInfo {
1616
where_,
1717
generic_params,

godot-macros/src/derive/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
99
mod derive_export;
1010
mod derive_from_variant;
11-
mod derive_godot_compatible;
11+
mod derive_godot_convert;
1212
mod derive_property;
1313
mod derive_to_variant;
1414

1515
pub(crate) use derive_export::*;
1616
pub(crate) use derive_from_variant::*;
17-
pub(crate) use derive_godot_compatible::*;
17+
pub(crate) use derive_godot_convert::*;
1818
pub(crate) use derive_property::*;
1919
pub(crate) use derive_to_variant::*;

godot-macros/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,8 +443,8 @@ pub fn godot_api(_meta: TokenStream, input: TokenStream) -> TokenStream {
443443
}
444444

445445
#[proc_macro_derive(GodotConvert)]
446-
pub fn derive_godot_compatible(input: TokenStream) -> TokenStream {
447-
translate(input, derive::derive_godot_compatible)
446+
pub fn derive_godot_convert(input: TokenStream) -> TokenStream {
447+
translate(input, derive::derive_godot_convert)
448448
}
449449

450450
/// Derive macro for [ToGodot](../builtin/meta/trait.ToGodot.html) on structs or enums.

0 commit comments

Comments
 (0)