-
-
Notifications
You must be signed in to change notification settings - Fork 214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document and refactor PluginItem
related stuff
#1003
Conversation
d1f40a9
to
bfe2b8d
Compare
API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-1003 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for the clean up 🙂
Where I'm not exactly sure from the changes, how would the process of e.g. adding a new property to Struct
look now, vs. before? It seems there are now more places that one needs to keep track of and update, no?
/// # Safety | ||
/// | ||
/// `obj` must be castable to `T`. | ||
pub unsafe fn dynify_fn<T, D>(obj: Gd<Object>) -> ErasedDynGd |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might need #[deny(unsafe_op_in_unsafe_fn)]
.
godot-core/src/registry/class.rs
Outdated
/// This only looks for an `AsDyn<D>` implementation in the dynamic class, the conversion will fail if the dynamic class doesn't | ||
/// implement `AsDyn<D>` even if there exists some superclass that does implement `AsDyn<D>`. This restriction could in theory be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe upgrade ,
-> ;
and add another ,
🙂
/// This only looks for an `AsDyn<D>` implementation in the dynamic class, the conversion will fail if the dynamic class doesn't | |
/// implement `AsDyn<D>` even if there exists some superclass that does implement `AsDyn<D>`. This restriction could in theory be | |
/// This only looks for an `AsDyn<D>` implementation in the dynamic class; the conversion will fail if the dynamic class doesn't | |
/// implement `AsDyn<D>`, even if there exists some superclass that does implement `AsDyn<D>`. This restriction could in theory be |
godot-core/src/registry/plugin.rs
Outdated
/// The type id of the trait object this was registered with. | ||
pub fn dyn_trait_typeid(&self) -> &any::TypeId { | ||
&self.dyn_trait_typeid | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeId
implements Copy
. Although its docs don't specifically mention that it's "lightweight", we can probably assume that it's likely some sort of integer. Should we return by value, like we do with Vector4
, Quaternion
etc?
godot-core/src/registry/plugin.rs
Outdated
// SAFETY: `DynTraitImpl::new` ensures that this function is safe to call when `object` is castable to `self.class_name`. | ||
// Since the dynamic class of `object` is `self.class_name`, it must be castable to `self.class_name`. | ||
let erased_dyn = unsafe { (self.erased_dynify_fn)(object.upcast_object()) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should upcast_object()
be lifted out of the unsafe
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think that makes sense, as is it may not be entirely clear that it's calling the erased_dynify_fn
that is unsafe.
godot-core/src/registry/plugin.rs
Outdated
|
||
/// Convert a [`Gd<T>`] to a [`DynGd<T, D>`] using `self`. | ||
/// | ||
/// This will fail if the dynamic class of `object` does not match the [`ClassName`] stored in `self`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// This will fail if the dynamic class of `object` does not match the [`ClassName`] stored in `self`. | |
/// This will fail with `Err(object)` if the dynamic class of `object` does not match the [`ClassName`] stored in `self`. |
let item_constructor = quote! { { | ||
let mut item = #prv::ITraitImpl::new::<#class_name>(#docs); | ||
#(#modifiers)* | ||
item | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let item_constructor = quote! { { | |
let mut item = #prv::ITraitImpl::new::<#class_name>(#docs); | |
#(#modifiers)* | |
item | |
} | |
}; | |
let item_constructor = quote! { | |
{ | |
let mut item = #prv::ITraitImpl::new::<#class_name>(#docs); | |
#(#modifiers)* | |
item | |
} | |
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also not 100% sure if "modifiers" is such a good term here -- it's typically used to denote values (flags as in Ctrl/Shift/...).
Since the inserted code aren't modifiers themselves but rather modifications, maybe name it something like item_modifications
or item_updates
?
(This mostly applies to the 2nd variable declaration; the list of (cfg_attrs, ident)
is probably ok with the existing name).
godot-macros/src/docs.rs
Outdated
} | ||
}) | ||
})() | ||
.unwrap_or(quote! { docs: None }) | ||
.unwrap_or(TokenStream::new()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Damn, we still have this (|| { ... })()
pattern 😁
I need to make a note to clean this up at some point...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this actually doesnt work properly, i didnt check with register-docs
enabled at first so i missed that this was wrong
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i replaced this occurence with a let-else while i was at it
godot-core/src/registry/plugin.rs
Outdated
pub(crate) is_instantiable: bool, | ||
#[cfg(all(since_api = "4.3", feature = "register-docs"))] | ||
pub(crate) docs: Option<StructDocs>, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub(crate) is_instantiable: bool, | |
#[cfg(all(since_api = "4.3", feature = "register-docs"))] | |
pub(crate) docs: Option<StructDocs>, | |
} | |
pub(crate) is_instantiable: bool, | |
/// Documentation extracted from the struct's RustDoc. | |
#[cfg(all(since_api = "4.3", feature = "register-docs"))] | |
pub(crate) docs: Option<StructDocs>, | |
} |
godot-core/src/registry/plugin.rs
Outdated
@@ -5,38 +5,67 @@ | |||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. | |||
*/ | |||
|
|||
use crate::classes::Object; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe use the qualified version classes::Object
in code, since classes
is already imported below?
godot-core/src/registry/plugin.rs
Outdated
pub fn with_generated<T: GodotClass + cap::GodotDefault>(mut self) -> Self { | ||
set(&mut self.generated_create_fn, callbacks::create::<T>); | ||
#[cfg(since_api = "4.2")] | ||
{ | ||
set(&mut self.generated_recreate_fn, callbacks::recreate::<T>); | ||
} | ||
self | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need the { }
, or could it just be
pub fn with_generated<T: GodotClass + cap::GodotDefault>(mut self) -> Self { | |
set(&mut self.generated_create_fn, callbacks::create::<T>); | |
#[cfg(since_api = "4.2")] | |
{ | |
set(&mut self.generated_recreate_fn, callbacks::recreate::<T>); | |
} | |
self | |
} | |
pub fn with_generated<T: GodotClass + cap::GodotDefault>(mut self) -> Self { | |
set(&mut self.generated_create_fn, callbacks::create::<T>); | |
#[cfg(since_api = "4.2")] | |
set(&mut self.generated_recreate_fn, callbacks::recreate::<T>); | |
self | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh yeah i guess it does, i think it used to be an assignment, and it doesn't work for assignments.
bfe2b8d
to
76ffad8
Compare
So what you need to do to add a field to
Then the two diverge, for the old implementation: For the new implementation: How you choose to split these up into individual steps exactly is a matter of taste, but it's not a big difference to me at least. |
76ffad8
to
030c7b0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me!
Since you mentioned this might conflict with #998, could you coordinate the two?
To me it doesn't matter which one is merged first, but since this PR is quite foundational and has high conflict risk for any changes in the plugin registration, it would be good to merge it soon. If #998 takes more than a couple of days, I'd say we merge this first and address the conflicts in that other PR. Makes sense?
7dab4fd
to
9f0f65b
Compare
godot-core/src/registry/plugin.rs
Outdated
// Wrapper needed because Debug can't be derived on function pointers with reference parameters, so this won't work: | ||
// pub type ErasedRegisterFn = fn(&mut dyn std::any::Any); | ||
// A wrapper is needed here because Debug can't be derived on function pointers with reference parameters, so this won't work: | ||
// `pub type ErasedRegisterFn = fn(&mut dyn std::any::Any);`` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two backticks at the end.
Also, we don't handle backticking in //
comments very consistently, and I don't think it should follow the same rules -- as these comments are never formatted, a backtick doesn't help much with readability (unless it's maybe inline text, where it's unclear which are code symbols, but even there that's often clear from the context).
For separate lines that show code, I wouldn't backtick them. If there's a bigger code block, having empty lines in between is more effective.
(Also below).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i like having them there but i also dont really mind either way, so i removed them
Make constructors + builders for the structs Move more things out of proc-macros and into struct constructors/builders Rework the safety invariants of `godot_dyn` Document lots of these apis better
9f0f65b
to
5cd8fa1
Compare
Thank you! |
PluginItem
into separate structs per variantgodot_dyn
Whether using builders in here is an improvement isn't 100% clear always. It could be used for the builder-api later, but it's also a bit low-level at the moment. And may be split at the wrong level of granularity. It does however reduce a lot of code in the proc-macros, which is an advantage.
The
DynTraitImpl
refactor i think works pretty well, a lot of the safety invariants have been moved into the type system, and we dont need to generate much unsafe code in the proc-macro anymore. I also removedDynToClassRelation
and replaced it withDynTraitImpl
to simplify some of the code.We could maybe make a util-struct that generates code to use the builders, however currently it's only used in two places so im not sure it's much of an advantage yet. However in the future it may be useful if we're gonna be using the builder-api under the hood.
Git is very confused by the
PluginItem
refactor unfortunately. It should largely be the same as it was before but just split up, except forDynTraitImpl
. However there was an upstream change to the plugin items while i was working on this which made a bit of a messy merge, but i think i resolved it properly.