-
-
Notifications
You must be signed in to change notification settings - Fork 222
Experiment with splitting up signature differently #1042
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
base: master
Are you sure you want to change the base?
Conversation
API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-1042 |
a0f9079
to
f2411b0
Compare
ae505cf
to
e29f2f8
Compare
Im gonna do another pass at cleaning up some minor things later, but all the functionality is in place so im marking it ready for review |
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! 👍
This change now leaks a new type to the public API:
fn param_info(
index: usize,
param_name: &str
) -> Option<MethodParamOrReturnInfo>
However MethodParamOrReturnInfo
is not public.
What's the general idea of APIs, in terms of what's public?
godot-core/src/task/futures.rs
Outdated
@@ -298,7 +300,9 @@ impl<C: WithBaseField, R: ParamTuple + Sync + Send> TypedSignal<'_, C, R> { | |||
} | |||
} | |||
|
|||
impl<C: WithBaseField, R: ParamTuple + Sync + Send> IntoFuture for &TypedSignal<'_, C, R> { | |||
impl<C: WithBaseField, R: InParamTuple + Sync + Send + 'static> IntoFuture |
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.
Any reason why this adds 'static
bound?
Also in some other places...
InParamTuple
can maybe not be 'static
itself, if RefArg
or so is used?
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.
It adds a 'static
bound because ParamTuple
had a 'static
bound before and TypedSignal
relied on that.
And yeah, i don't remember exactly where but there are cases where ParamTuple
can't be 'static
.
unsafe_impl_param_tuple!(13; (p0, 0): P0, (p1, 1): P1, (p2, 2): P2, (p3, 3): P3, (p4, 4): P4, (p5, 5): P5, (p6, 6): P6, (p7, 7): P7, (p8, 8): P8, (p9, 9): P9, (p10, 10): P10, (p11, 11): P11, (p12, 12): P12); | ||
unsafe_impl_param_tuple!(14; (p0, 0): P0, (p1, 1): P1, (p2, 2): P2, (p3, 3): P3, (p4, 4): P4, (p5, 5): P5, (p6, 6): P6, (p7, 7): P7, (p8, 8): P8, (p9, 9): P9, (p10, 10): P10, (p11, 11): P11, (p12, 12): P12, (p13, 13): P13); | ||
|
||
// Manually implement for () so we dont have to add a bunch of #[allow(..)] above for the 0-length case. |
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'd rather have such #[allow]
s than manually duplicating code that can be generated by the macro.
They can also cover an entire impls
module or so.
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 mainly dont like it because it can be useful to have those lints for the code, though i think it may be possible to generate them only when necessary?
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.
Yes, the question is how much indirection this adds if it's handled inside the macro. Having complex de-linting logic may be overkill.
Otherwise, would this potentially work?
#[allow(bla)]
mod impl0 {
// macro invocation for 0
}
mod impls {
// others
}
use crate::meta::{signature, CallContext}; | ||
use crate::meta::{ | ||
FromGodot, GodotConvert, GodotFfiVariant, GodotType, InParamTuple, OutParamTuple, ParamTuple, | ||
ToGodot, | ||
}; |
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.
These 2 can be combined 🙂
format!( | ||
// This repeat expression is basically just `"{$p:?}"`, the rest is only needed so that | ||
// the repetition separator can be `", "` instead of `,`. | ||
concat!("" $(, "{", stringify!($p), ":?}" ,)", "*), | ||
$($p=$p),* | ||
) |
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.
Would it not be easier to use positional format args?
Then you don't need stringify!($p)
and the expression is already much simpler.
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 true, i didnt think of that actually
godot-core/src/meta/param_tuple.rs
Outdated
/// As an example, this would be used to call Godot functions through ffi, however this is _not_ used when Godot calls a user-defined | ||
/// function. |
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.
/// As an example, this would be used to call Godot functions through ffi, however this is _not_ used when Godot calls a user-defined | |
/// function. | |
/// As an example, this would be used to call Godot functions through FFI, however this is _not_ used when Godot calls a user-defined | |
/// function. |
godot-core/src/registry/method.rs
Outdated
use crate::obj::GodotClass; | ||
|
||
/// Info relating to an argument or return type in a method. | ||
pub struct MethodParamOrReturnInfo { | ||
info: PropertyInfo, | ||
pub info: PropertyInfo, |
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.
Making this pub
is intended?
See also main comment about MethodParamOrReturnInfo
, which is currently not public. If it becomes public, we should probably think about the encapsulation.
/// Fully customizable connection setup. | ||
/// | ||
/// The returned builder provides several methods to configure how to connect the signal. It needs to be finalized with a call to | ||
/// [`ConnectBuilder::done()`]. | ||
pub fn connect_builder(&mut self) -> ConnectBuilder<'_, 'c, C, (), Ps, ()> { | ||
ConnectBuilder::new(self) | ||
} | ||
|
||
/// Directly connect a Rust callable `godot_fn`, with a name based on `F`. | ||
/// | ||
/// This exists as a short-hand for the connect methods on [`TypedSignal`] and avoids the generic instantiation of the full-blown | ||
/// type state builder for simple + common connections, thus hopefully being a tiny bit lighter on compile times. | ||
fn inner_connect_godot_fn<F>( | ||
&mut self, | ||
godot_fn: impl FnMut(&[&Variant]) -> Result<Variant, ()> + 'static, | ||
) { | ||
let callable_name = make_callable_name::<F>(); | ||
let callable = Callable::from_local_fn(&callable_name, godot_fn); | ||
|
||
let signal_name = self.name.as_ref(); | ||
self.owner.with_object_mut(|obj| { | ||
obj.connect(signal_name, &callable); | ||
}); | ||
} | ||
|
||
/// Connect an untyped callable, with optional flags. | ||
/// | ||
/// Used by [`ConnectBuilder::done()`]. Any other type-state (such as thread-local/sync, callable debug name, etc.) are baked into | ||
/// `callable` and thus type-erased into runtime logic. | ||
pub(super) fn inner_connect_untyped( | ||
&mut self, | ||
callable: &Callable, | ||
flags: Option<ConnectFlags>, | ||
) { | ||
use crate::obj::EngineBitfield; | ||
|
||
let signal_name = self.name.as_ref(); | ||
|
||
self.owner.with_object_mut(|obj| { | ||
let mut c = obj.connect_ex(signal_name, callable); | ||
if let Some(flags) = flags { | ||
c = c.flags(flags.ord() as u32); | ||
} | ||
c.done(); | ||
}); | ||
} | ||
|
||
pub(crate) fn to_untyped(&self) -> crate::builtin::Signal { | ||
crate::builtin::Signal::from_object_signal(&self.receiver_object(), &*self.name) | ||
} | ||
} |
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.
Moving those up changes the order of declaration, which no longer documents the symbols in order of importance.
See
- https://godot-rust.github.io/docs/gdext/pr-1042/godot/register/struct.TypedSignal.html#implementations
- https://godot-rust.github.io/docs/gdext/master/godot/register/struct.TypedSignal.html#implementations
Could you restore the order?
godot-codegen/src/util.rs
Outdated
use crate::meta::{AsArg, AsObjectArg, ClassName, CowArg, ObjectArg, ObjectCow, RefArg}; | ||
use crate::meta::{ParamTuple, InParamTuple, OutParamTuple, Signature}; |
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.
Also here can be combined 🙂
godot-core/src/meta/signature.rs
Outdated
|
||
use godot_ffi as sys; | ||
use sys::{BuiltinMethodBind, ClassMethodBind, GodotFfi, UtilityFunctionBind}; | ||
use std::{borrow::Cow, fmt, marker::PhantomData}; |
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.
Please flatten
godot-core/src/meta/signature.rs
Outdated
/// Performs a ptrcall and processes the return value to give nice error output. | ||
/// | ||
/// # Safety | ||
/// | ||
/// This calls [`GodotFfi::new_with_init`] and passes the ptr as the second argument to `f`, see that function for safety docs. | ||
unsafe fn perform_ptrcall( |
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.
The brief description of the method is good, but "perform" doesn't carry any of that information. Is it maybe possible to make the name a bit more descriptive, even if longer?
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 can't really think of anything that's of similar length, but maybe just perform_ptrcall_and_process_return
works?
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.
"process" isn't much better... I'd like to avoid generic filler words; if it's not easy to add more context, let's keep it short.
Maybe something highlighting that this operates on the raw FFI args/ret: raw_ptrcall(...)
That would at least differentiate it from the other functions like out_builtin_ptrcall
and so on.
Hm yeah, |
macro_rules! unsafe_impl_param_tuple { | ||
($Len:literal; $(($p:ident, $n:tt): $P:ident),+) => { | ||
impl<$($P),+> ParamTuple for ($($P,)+) where $($P: GodotConvert + fmt::Debug),+ { | ||
const LEN: usize = $Len; |
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.
you can count the number of $P
s with something like this and don't have to manually maintain the count:
(count_items; $PP:ident, $($P:ident),+) => {
1 + unsafe_impl_param_tuple!(count_items; $($P),+)
};
(count_items; $P:ident) => {
1
};
and:
const LEN: usize = unsafe_impl_param_tuple!(count_items; $($P),+);
dcd467b
to
4d5e63a
Compare
Since I caused merge conflicts with #1111, I added a commit to resolve them. I hope I added the new traits in the right places. Feel free to do whatever with it (including revert/change/...), don't need to keep authorship either 🙂 |
f5dc50c
to
7578d86
Compare
remove signature from compiling merge `ParamList` with `ParamTuple` some cleanup docs changes from code review
7578d86
to
3aac094
Compare
VarcallSignatureTuple
andPtrcallSignatureTuple
are now a structSignature<Params, Ret>
. The behavior of the params are in a new set of traits:ParamList
,InParamList
andOutParamList
.This split allows input parameters and output parameters to be treated differently, for instance this makes it so that only
FromGodot
is needed for user-defined functions.Should probably be coordinated with #1000 if we actually want to add it, as both this PR and that PR adds a generic type for parameter tuples.
Currently I've just added the new signature stuff to a separate file, rather than overwriting
signature.rs
. Mostly to make it easier to read here in the diff and such. This would be changed if we go with this. This needs a lot of cleanup in general lol.But i wanna at least run the minimal CI on it here and get feedback on if this is the strategy we want to go for before i like polish it up. Since there are other strategies we could go with. The main concrete issue this really solves is splitting up parameters based on if they're in an in vs out call.
I'm not entirely sure if this is a breaking change, i think it isnt? It should just make code that used to not compile, compile. And it doesn't change any public symbols.