Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 28 additions & 21 deletions derive/src/impl_attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ pub fn godot_script_impl(
};

let method_flag = if is_static {
quote!(#godot_types::global::MethodFlags::STATIC)
quote!(.with_flags(#godot_types::global::MethodFlags::STATIC))
} else {
quote!(#godot_types::global::MethodFlags::NORMAL)
TokenStream::new()
};

let description = fnc.attrs.iter()
Expand All @@ -128,32 +128,38 @@ pub fn godot_script_impl(

let metadata = quote_spanned! {
fnc.span() =>
::godot_rust_script::private_export::RustScriptMethodDesc {
name: #fn_name_str,
arguments: Box::new([#args_meta]),
return_type: ::godot_rust_script::private_export::RustScriptPropDesc {
name: #fn_name_str,
ty: #fn_return_ty,
class_name: <<#fn_return_ty_rust as #godot_types::meta::GodotConvert>::Via as #godot_types::meta::GodotType>::class_id(),
usage: #godot_types::global::PropertyUsageFlags::NONE,
hint: #property_hints::NONE,
hint_string: String::new(),
description: "",
},
flags: #method_flag,
description: concat!(#description),
},
methods.add_method(
::godot_rust_script::private_export::RustScriptMethodDesc::builder(
#fn_name_str,
Box::new([#args_meta]),
::godot_rust_script::private_export::RustScriptPropDesc {
name: #fn_name_str,
ty: #fn_return_ty,
class_name: <<#fn_return_ty_rust as #godot_types::meta::GodotConvert>::Via as #godot_types::meta::GodotType>::class_id(),
usage: #godot_types::global::PropertyUsageFlags::NONE,
hint: #property_hints::NONE,
hint_string: String::new(),
description: "",
},
)
.with_description(concat!(#description))
#method_flag
);
};

Ok((dispatch, metadata))
})
.collect();

let (method_dispatch, method_metadata): (TokenStream, TokenStream) = match result {
Ok(r) => r.into_iter().unzip(),
let method_list = match result {
Ok(r) => r,
Err(err) => return err,
};

let method_count = method_list.len();
let (method_dispatch, method_metadata): (TokenStream, TokenStream) =
method_list.into_iter().unzip();

let trait_impl = quote_spanned! {
current_type.span() =>
impl ::godot_rust_script::GodotScriptImpl for #current_type {
Expand All @@ -173,9 +179,10 @@ pub fn godot_script_impl(
let metadata = quote! {
::godot_rust_script::register_script_methods!(
#current_type,
vec![
#method_count,
methods => {
#method_metadata
]
}
);
};

Expand Down
4 changes: 2 additions & 2 deletions rust-script/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ impl<T: GodotScript, B: Inherits<T::Base> + Inherits<Object>> CastToScript<T> fo

/// Script property access indirection
///
/// gdext uses this kind of indirection to allow conversion of the actual property value into a godot compatible type when accessing the
/// Gdext uses this kind of indirection to allow conversion of the actual property value into a Godot compatible type when accessing the
/// property from the engine. This Trait separates the `::godot::prelude::Var` trait into it's get and set components for more granular
/// requirements on the property types.
pub trait GetScriptProperty: GodotConvert {
Expand All @@ -222,7 +222,7 @@ pub trait GetScriptProperty: GodotConvert {

/// Script property write indirection
///
/// gdext uses this kind of indirection to allow conversion of the actual property value from a godot compatible type when setting the
/// Gdext uses this kind of indirection to allow conversion of the actual property value from a Godot compatible type when setting the
/// property from the engine. This Trait separates the `::godot::prelude::Var` trait into it's get and set components for more granular
/// requirements on the property types.
pub trait SetScriptProperty: GodotConvert {
Expand Down
14 changes: 7 additions & 7 deletions rust-script/src/runtime/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,26 +140,26 @@ pub struct Documented<T> {
description: &'static str,
}

impl From<crate::static_script_registry::RustScriptPropertyInfo> for Documented<PropertyInfo> {
fn from(value: crate::static_script_registry::RustScriptPropertyInfo) -> Self {
impl From<crate::static_script_registry::RustScriptPropDesc> for Documented<PropertyInfo> {
fn from(value: crate::static_script_registry::RustScriptPropDesc) -> Self {
Self {
description: value.description,
inner: (&value).into(),
}
}
}

impl From<crate::static_script_registry::RustScriptMethodInfo> for Documented<MethodInfo> {
fn from(value: crate::static_script_registry::RustScriptMethodInfo) -> Self {
impl From<crate::static_script_registry::RustScriptMethodDesc> for Documented<MethodInfo> {
fn from(value: crate::static_script_registry::RustScriptMethodDesc) -> Self {
Self {
description: value.description,
inner: (&value).into(),
inner: value.into(),
}
}
}

impl From<crate::static_script_registry::RustScriptSignalInfo> for Documented<MethodInfo> {
fn from(value: crate::static_script_registry::RustScriptSignalInfo) -> Self {
impl From<crate::static_script_registry::RustScriptSignalDesc> for Documented<MethodInfo> {
fn from(value: crate::static_script_registry::RustScriptSignalDesc) -> Self {
Self {
description: value.description,
inner: (&value).into(),
Expand Down
82 changes: 44 additions & 38 deletions rust-script/src/runtime/rust_script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use godot::prelude::{
};

use crate::apply::Apply;
use crate::static_script_registry::RustScriptPropertyInfo;
use crate::private_export::RustScriptPropDesc;

use super::rust_script_instance::GodotScriptObject;
use super::{
Expand All @@ -39,7 +39,7 @@ pub(crate) struct RustScript {
#[var(get = get_class_name, set = set_class_name, usage_flags = [STORAGE])]
class_name: GString,

/// dummy property that stores the onwer ids when the extension gets reloaded by the engine.
/// Dummy property that stores the owner ids when the extension gets reloaded by the engine.
#[var( get = owner_ids, set = set_owner_ids, usage_flags = [STORAGE])]
#[allow(dead_code)]
owner_ids: Array<i64>,
Expand Down Expand Up @@ -94,7 +94,7 @@ impl RustScript {
#[func]
fn set_owner_ids(&mut self, ids: Array<i64>) {
if ids.is_empty() {
// ignore empty owners list from engine
// Ignore empty owners list from engine
return;
}

Expand Down Expand Up @@ -133,7 +133,7 @@ impl RustScript {
base.call("_init", &[]);
}

fn map_property_info_list<R>(&self, f: impl Fn(&RustScriptPropertyInfo) -> R) -> Vec<R> {
fn map_property_info_list<R>(&self, f: impl Fn(&RustScriptPropDesc) -> R) -> Vec<R> {
let reg = SCRIPT_REGISTRY.read().expect("unable to obtain read lock");

reg.get(&self.str_class_name())
Expand Down Expand Up @@ -218,44 +218,48 @@ impl IScriptExtension for RustScript {
}

fn has_property_default_value(&self, _property: StringName) -> bool {
// default values are currently not exposed
// Default values are currently not exposed
false
}

fn get_property_default_value(&self, #[expect(unused)] property: StringName) -> Variant {
// default values are currently not exposed
// Default values are currently not exposed
Variant::nil()
}

fn get_script_signal_list(&self) -> Array<VarDictionary> {
let Some(script) = RustScriptLanguage::script_meta_data(&self.str_class_name()) else {
godot_error!(
"RustScript class {} does not exist in compiled dynamic library!",
self.str_class_name()
);
return Array::new();
};
RustScriptLanguage::with_script_metadata(&self.str_class_name(), |script_data| {
let Some(script) = script_data else {
godot_error!(
"RustScript class {} does not exist in compiled dynamic library!",
self.str_class_name()
);
return Array::new();
};

script
.signals()
.iter()
.map(|signal| MethodInfo::from(signal).to_dict())
.collect()
script
.signals()
.iter()
.map(|signal| MethodInfo::from(signal).to_dict())
.collect()
})
}

fn has_script_signal(&self, name: StringName) -> bool {
let Some(script) = RustScriptLanguage::script_meta_data(&self.str_class_name()) else {
godot_error!(
"RustScript class {} does not exist in compiled dynamic library!",
self.str_class_name()
);
return false;
};
RustScriptLanguage::with_script_metadata(&self.str_class_name(), |script_data| {
let Some(script) = script_data else {
godot_error!(
"RustScript class {} does not exist in compiled dynamic library!",
self.str_class_name()
);
return false;
};

script
.signals()
.iter()
.any(|signal| signal.name == name.to_string())
script
.signals()
.iter()
.any(|signal| signal.name == name.to_string())
})
}

fn update_exports(&mut self) {}
Expand All @@ -268,7 +272,7 @@ impl IScriptExtension for RustScript {
class
.methods()
.iter()
.map(|method| MethodInfo::from(method).to_dict())
.map(|method| MethodInfo::from(method.clone()).to_dict())
.collect()
})
.unwrap_or_default()
Expand All @@ -295,7 +299,7 @@ impl IScriptExtension for RustScript {
class
.methods()
.iter()
.any(|method| method.method_name == method_name.to_string())
.any(|method| method.name == method_name.to_string())
})
}

Expand All @@ -310,8 +314,8 @@ impl IScriptExtension for RustScript {
class
.methods()
.iter()
.find(|method| method.method_name == method_name.to_string())
.map(|method| MethodInfo::from(method).to_dict())
.find(|method| method.name == method_name.to_string())
.map(|method| MethodInfo::from(method.clone()).to_dict())
})
.unwrap_or_default()
}
Expand Down Expand Up @@ -386,10 +390,10 @@ impl IScriptExtension for RustScript {
true
}

// godot script reload hook
// Godot script reload hook
fn reload(
&mut self,
// before 4.4 the engine does not correctly pass the keep_state flag
// Before 4.4 the engine does not correctly pass the keep_state flag
#[cfg_attr(before_api = "4.4", expect(unused_variables))] keep_state: bool,
) -> godot::global::Error {
#[cfg(before_api = "4.4")]
Expand All @@ -398,7 +402,9 @@ impl IScriptExtension for RustScript {
let owners = self.owners.borrow().clone();
let exported_properties_list = if keep_state {
self.map_property_info_list(|prop| {
(prop.usage & PropertyUsageFlags::EDITOR.ord() != 0).then_some(prop.property_name)
(prop.usage.ord() & PropertyUsageFlags::EDITOR.ord()
!= PropertyUsageFlags::NONE.ord())
.then_some(prop.name)
})
} else {
Vec::with_capacity(0)
Expand Down Expand Up @@ -427,7 +433,7 @@ impl IScriptExtension for RustScript {
Vec::with_capacity(0)
};

// clear script to destroy script instance.
// Clear script to destroy script instance.
object.set_script(Option::<&Gd<Script>>::None);

self.downgrade_gd(|self_gd| {
Expand Down Expand Up @@ -497,7 +503,7 @@ impl IScriptExtension for RustScript {
class
.properties()
.iter()
.map(|prop| StringName::from(prop.property_name))
.map(|prop| StringName::from(prop.name))
.collect()
})
.unwrap_or_default()
Expand Down
8 changes: 7 additions & 1 deletion rust-script/src/runtime/rust_script_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ fn script_method_list(script: &Gd<RustScript>) -> Box<[MethodInfo]> {
.read()
.expect("script registry is inaccessible")
.get(&class_name)
.map(|meta| meta.methods().iter().map(MethodInfo::from).collect())
.map(|meta| {
meta.methods()
.iter()
.cloned()
.map(MethodInfo::from)
.collect()
})
.unwrap_or_else(|| Box::new([]) as Box<[MethodInfo]>);

methods
Expand Down
32 changes: 18 additions & 14 deletions rust-script/src/runtime/rust_script_language.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,14 @@ impl RustScriptLanguage {
.map(|gd| gd.cast())
}

pub fn script_meta_data(class_name: &str) -> Option<RustScriptMetaData> {
let reg = SCRIPT_REGISTRY
.read()
.expect("unable to obtain read access");
#[inline]
pub fn with_script_metadata<R>(
class_name: &str,
lambda: impl FnOnce(Option<&RustScriptMetaData>) -> R,
) -> R {
let reg = SCRIPT_REGISTRY.read().expect("registry is poisoned");

reg.get(class_name).map(ToOwned::to_owned)
lambda(reg.get(class_name))
}
}

Expand All @@ -89,10 +91,10 @@ impl IScriptLanguageExtension for RustScriptLanguage {
true
}

/// thread enter hook will be called before entering a thread
/// Thread enter hook will be called before entering a thread
fn thread_enter(&mut self) {}

/// thread exit hook will be called before leaving a thread
/// Thread exit hook will be called before leaving a thread
fn thread_exit(&mut self) {}

fn get_public_functions(&self) -> Array<VarDictionary> {
Expand Down Expand Up @@ -184,13 +186,15 @@ impl IScriptLanguageExtension for RustScriptLanguage {
fn get_global_class_name(&self, path: GString) -> VarDictionary {
let class_name = Self::path_to_class_name(&path);

let Some(script) = Self::script_meta_data(&class_name) else {
return VarDictionary::new();
};
Self::with_script_metadata(&class_name, |script_data| {
let Some(script) = script_data else {
return VarDictionary::new();
};

VarDictionary::new().apply(|dict| {
dict.set("name", class_name);
dict.set("base_type", script.base_type_name());
VarDictionary::new().apply(|dict| {
dict.set("name", &*class_name);
dict.set("base_type", script.base_type_name());
})
})
}

Expand All @@ -204,7 +208,7 @@ impl IScriptLanguageExtension for RustScriptLanguage {
_line: i32,
_col: i32,
) -> global::Error {
// TODO: From Godot 4.4 we can show an editor toast here. Just waiting for a new gdext release.
// TODO: From Godot 4.4 we can show an editor toast here. Just waiting for a new Gdext release.
godot_error!("Editing rust scripts from inside Godot is currently not supported.");

global::Error::OK
Expand Down
Loading
Loading