Skip to content

Commit

Permalink
change to export info struct instead of trait
Browse files Browse the repository at this point in the history
  • Loading branch information
lilizoey committed May 1, 2023
1 parent a36a002 commit 06d0da0
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 83 deletions.
26 changes: 13 additions & 13 deletions godot-core/src/builtin/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use godot_ffi as sys;

use crate::builtin::meta::VariantMetadata;
use crate::builtin::*;
use crate::export::{Export, ExportDefaultInfo, TypeString};
use crate::export::{Export, ExportInfo, TypeString};
use crate::obj::Share;
use std::fmt;
use std::marker::PhantomData;
Expand Down Expand Up @@ -621,18 +621,6 @@ impl<T: VariantMetadata> Share for Array<T> {
}
}

impl<T: VariantMetadata + TypeString> ExportDefaultInfo for Array<T> {
fn default_property_hint() -> crate::engine::global::PropertyHint {
crate::engine::global::PropertyHint::PROPERTY_HINT_TYPE_STRING
}

fn default_property_hint_string() -> GodotString {
T::type_string().into()
}
}

impl ExportDefaultInfo for Array<Variant> {}

impl<T: VariantMetadata + TypeString> TypeString for Array<T> {
fn type_string() -> String {
format!("{}:{}", sys::VariantType::Array as i32, T::type_string())
Expand All @@ -643,12 +631,24 @@ impl<T: VariantMetadata + TypeString> Export for Array<T> {
fn export(&self) -> Self {
self.share()
}

fn default_export_info() -> ExportInfo {
ExportInfo {
variant_type: Self::variant_type(),
hint: crate::engine::global::PropertyHint::PROPERTY_HINT_TYPE_STRING,
hint_string: T::type_string().into(),
}
}
}

impl Export for Array<Variant> {
fn export(&self) -> Self {
self.share()
}

fn default_export_info() -> ExportInfo {
ExportInfo::new_none(Self::variant_type())
}
}

impl<T: VariantMetadata> Default for Array<T> {
Expand Down
9 changes: 6 additions & 3 deletions godot-core/src/builtin/dictionary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@

use godot_ffi as sys;

use crate::builtin::meta::VariantMetadata;
use crate::builtin::{inner, FromVariant, ToVariant, Variant};
use crate::export::{Export, ExportDefaultInfo};
use crate::export::{Export, ExportInfo};
use crate::obj::Share;
use std::fmt;
use std::marker::PhantomData;
Expand Down Expand Up @@ -301,12 +302,14 @@ impl Share for Dictionary {
}
}

impl ExportDefaultInfo for Dictionary {}

impl Export for Dictionary {
fn export(&self) -> Self {
self.share()
}

fn default_export_info() -> ExportInfo {
ExportInfo::new_none(Self::variant_type())
}
}

// ----------------------------------------------------------------------------------------------------------------------------------------------
Expand Down
85 changes: 53 additions & 32 deletions godot-core/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,76 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use crate::builtin::GodotString;
use crate::engine::global::PropertyHint;
use crate::builtin::meta::{ClassName, PropertyInfo};
use crate::builtin::{GodotString, StringName};
use crate::engine::global::{PropertyHint, PropertyUsageFlags};
use crate::obj::GodotClass;

use godot_ffi as sys;
use sys::VariantType;

/// Trait implemented for types that can be used as `#[export]` fields. This creates a copy of the
/// value, for some type-specific definition of "copy". For example, `Array` and `Gd` are returned
/// via `Share::share()` instead of copying the actual data.
pub trait Export: ExportDefaultInfo {
pub trait Export {
/// Creates a copy to be returned from a getter.
fn export(&self) -> Self;
}

/// Trait implemented for types that can be used in an `#[export]` field without specifying a custom `hint`
/// and `hint_string`.
pub trait ExportDefaultInfo {
/// The property hint to use when exporting properties if a custom one isn't specified.
fn default_property_hint() -> PropertyHint {
PropertyHint::PROPERTY_HINT_NONE
}
/// The export info to use for an exported field of this type, if no other export info is specified.
fn default_export_info() -> ExportInfo;
}

/// The property hint string to use when exporting properties if a custom one isn't specified.
fn default_property_hint_string() -> GodotString {
GodotString::new()
}
/// Info needed for godot to understand how to export a type to the editor.
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct ExportInfo {
pub variant_type: VariantType,
pub hint: PropertyHint,
pub hint_string: GodotString,
}

impl<T: ExportDefaultInfo> ExportDefaultInfo for Option<T> {
fn default_property_hint() -> PropertyHint {
T::default_property_hint()
impl ExportInfo {
/// Create a new `ExportInfo` with a property hint of
/// [`PROPERTY_HINT_NONE`](PropertyHint::PROPERTY_HINT_NONE).
pub fn new_none(variant_type: VariantType) -> Self {
Self {
variant_type,
hint: PropertyHint::PROPERTY_HINT_NONE,
hint_string: GodotString::new(),
}
}

fn default_property_hint_string() -> GodotString {
T::default_property_hint_string()
/// Create a `PropertyInfo` from this export info, using the given property_name and usage, as well as the class name of `C`.
pub fn to_property_info<C: GodotClass>(
self,
property_name: StringName,
usage: PropertyUsageFlags,
) -> PropertyInfo {
let Self {
variant_type,
hint,
hint_string,
} = self;

PropertyInfo {
variant_type,
class_name: ClassName::of::<C>(),
property_name,
hint,
hint_string,
usage,
}
}
}

impl<T: Export> Export for Option<T> {
fn export(&self) -> Self {
self.as_ref().map(|val| val.export())
}
}

// Implement ExportDefaultInfo for some various common types so people can use them without specifying a
// hint_type and hint_string.
impl ExportDefaultInfo for () {}
impl ExportDefaultInfo for String {}
impl ExportDefaultInfo for i128 {}
impl ExportDefaultInfo for isize {}
impl ExportDefaultInfo for u64 {}
impl ExportDefaultInfo for u128 {}
impl ExportDefaultInfo for usize {}
fn default_export_info() -> ExportInfo {
T::default_export_info()
}
}

/// Trait for types that can be represented as a type string for use with
/// [`PropertyHint::PROPERTY_HINT_TYPE_STRING`].
Expand All @@ -70,18 +88,21 @@ pub trait TypeString {

mod export_impls {
use super::*;
use crate::builtin::meta::VariantMetadata;
use crate::builtin::*;

macro_rules! impl_export_by_clone {
($Ty:ty => $variant_type:ident) => {
impl ExportDefaultInfo for $Ty {}

impl Export for $Ty {
fn export(&self) -> Self {
// If `Self` does not implement `Clone`, this gives a clearer error message
// than simply `self.clone()`.
Clone::clone(self)
}

fn default_export_info() -> ExportInfo {
ExportInfo::new_none(Self::variant_type())
}
}

impl TypeString for $Ty {
Expand Down
30 changes: 16 additions & 14 deletions godot-core/src/obj/gd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::builtin::{
Callable, FromVariant, GodotString, StringName, ToVariant, Variant, VariantConversionError,
};
use crate::engine::{Node, Object, Resource};
use crate::export::{Export, ExportDefaultInfo, TypeString};
use crate::export::{Export, ExportInfo, TypeString};
use crate::obj::dom::Domain as _;
use crate::obj::mem::Memory as _;
use crate::obj::{cap, dom, mem, EngineEnum, GodotClass, Inherits, Share};
Expand Down Expand Up @@ -657,7 +657,7 @@ impl<T: GodotClass> TypeString for Gd<T> {
fn type_string() -> String {
use engine::global::PropertyHint;

match Self::default_property_hint() {
match Self::default_export_info().hint {
hint @ (PropertyHint::PROPERTY_HINT_RESOURCE_TYPE
| PropertyHint::PROPERTY_HINT_NODE_TYPE) => {
format!(
Expand All @@ -672,27 +672,29 @@ impl<T: GodotClass> TypeString for Gd<T> {
}
}

impl<T: GodotClass> ExportDefaultInfo for Gd<T> {
fn default_property_hint() -> engine::global::PropertyHint {
if T::inherits::<Resource>() {
impl<T: GodotClass> Export for Gd<T> {
fn export(&self) -> Self {
self.share()
}

fn default_export_info() -> ExportInfo {
let hint = if T::inherits::<Resource>() {
engine::global::PropertyHint::PROPERTY_HINT_RESOURCE_TYPE
} else if T::inherits::<Node>() {
engine::global::PropertyHint::PROPERTY_HINT_NODE_TYPE
} else {
engine::global::PropertyHint::PROPERTY_HINT_NONE
}
}
};

fn default_property_hint_string() -> GodotString {
// Godot does this by default too, it doesn't seem to make a difference when not a resource/node
// but is needed when it is a resource/node.
T::CLASS_NAME.into()
}
}
let hint_string = T::CLASS_NAME.into();

impl<T: GodotClass> Export for Gd<T> {
fn export(&self) -> Self {
self.share()
ExportInfo {
variant_type: Self::variant_type(),
hint,
hint_string,
}
}
}

Expand Down
44 changes: 24 additions & 20 deletions godot-macros/src/derive_godot_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,18 +309,21 @@ fn make_exports_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
let field_ident = ident(&field_name);
let field_type = field.ty.clone();

let (hint_type, hint_string) = match export.hint.clone() {
Some(ExportHint {
hint_type,
description,
}) => (
quote! { ::godot::engine::global::PropertyHint::#hint_type },
quote! { ::godot::builtin::GodotString::from(#description) },
),
None => (
quote! { <#field_type as ::godot::export::ExportDefaultInfo>::default_property_hint() },
quote! { <#field_type as ::godot::export::ExportDefaultInfo>::default_property_hint_string() },
),
let export_info = quote! {
let mut export_info = <#field_type as ::godot::export::Export>::default_export_info();
};

let custom_hint = if let Some(ExportHint {
hint_type,
description,
}) = export.hint.clone()
{
quote! {
export_info.hint = ::godot::engine::global::PropertyHint::#hint_type;
export_info.hint_string = ::godot::builtin::GodotString::from(#description);
}
} else {
quote! {}
};

let getter_name;
Expand Down Expand Up @@ -379,14 +382,15 @@ fn make_exports_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
use ::godot::builtin::meta::VariantMetadata;

let class_name = ::godot::builtin::StringName::from(#class_name::CLASS_NAME);
let property_info = ::godot::builtin::meta::PropertyInfo {
variant_type: <#field_type>::variant_type(),
class_name: ::godot::builtin::meta::ClassName::of::<#class_name>(),
property_name: ::godot::builtin::StringName::from(#field_name),
hint: #hint_type,
hint_string: #hint_string,
usage: ::godot::engine::global::PropertyUsageFlags::PROPERTY_USAGE_DEFAULT,
};

#export_info

#custom_hint

let property_info = export_info.to_property_info::<#class_name>(
#field_name.into(),
::godot::engine::global::PropertyUsageFlags::PROPERTY_USAGE_DEFAULT
);
let property_info_sys = property_info.property_sys();

let getter_name = ::godot::builtin::StringName::from(#getter_name);
Expand Down
2 changes: 1 addition & 1 deletion godot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ pub mod prelude {
Node3DVirtual, NodeVirtual, Object, ObjectVirtual, PackedScene, PackedSceneVirtual,
RefCounted, RefCountedVirtual, Resource, ResourceVirtual, SceneTree, SceneTreeVirtual,
};
pub use super::export::{Export, ExportDefaultInfo, TypeString};
pub use super::export::{Export, TypeString};
pub use super::init::{gdextension, ExtensionLayer, ExtensionLibrary, InitHandle, InitLevel};
pub use super::log::*;
pub use super::obj::{Base, Gd, GdMut, GdRef, GodotClass, Inherits, InstanceId, Share};
Expand Down

0 comments on commit 06d0da0

Please sign in to comment.