-
-
Notifications
You must be signed in to change notification settings - Fork 114
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
glib: Decouple ObjectInterface impl from interface class struct #1384
Conversation
Yes I think that makes sense, both. Having the word class in the context of interfaces is just confusing, even if some GObject API calls it like that (
I think that would be nice, especially as it's just a bit of copy&paste. It is probably not useful often, but if you do a signals/properties-only interface then this would make it a bit less code to write (there are some such interfaces!). |
@@ -1317,6 +1317,15 @@ macro_rules! glib_object_wrapper { | |||
); | |||
}; | |||
|
|||
(@object_interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $iface:ty, |
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.
There's probably one branch of the macro that is not in use anymore now?
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 don't think so. There are three branch arms from top to bottom:
The short @interface
one is called by
gtk-rs-core/glib/src/wrapper.rs
Lines 416 to 431 in d849f56
// Interface | |
( | |
$(#[$attr:meta])* | |
$visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Interface<$ffi_name:ty $(, $ffi_class_name:ty)?>) $(@requires $($requires:path),+)?; | |
match fn { | |
type_ => || $get_type_expr:expr, | |
} | |
) => { | |
$crate::glib_object_wrapper!( | |
@interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, $ffi_name, | |
$( @ffi_class $ffi_class_name ,)? | |
@type_ $get_type_expr, | |
@requires [$( $($requires),+ )?] | |
); | |
}; |
The new @object_interface
one is called by
gtk-rs-core/glib/src/wrapper.rs
Lines 433 to 443 in d849f56
// ObjectInterface | |
( | |
$(#[$attr:meta])* | |
$visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (ObjectInterface<$iface_name:ty>) $(@requires $($requires:path),+)?; | |
) => { | |
$crate::glib_object_wrapper!( | |
@object_interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $iface_name, | |
@type_ $crate::translate::IntoGlib::into_glib(<$iface_name as $crate::subclass::interface::ObjectInterfaceType>::type_()), | |
@requires [$( $($requires),+ )?] | |
); | |
}; |
The full implementation is being subsequently used be the former two macros. Also empirically, deleting either of the branches causes errors somewhere. 😅
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.
Mh ok! This macro grew too much :)
glib/src/subclass/types.rs
Outdated
@@ -305,22 +323,22 @@ unsafe extern "C" fn interface_init<T: ObjectSubclass, A: IsImplementable<T>>( | |||
) where | |||
<A as ObjectType>::GlibClassType: Copy, | |||
{ | |||
let iface = &mut *(iface as *mut crate::Interface<A>); | |||
let klass = &mut *(iface as *mut crate::Interface<A>); |
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.
OOC, could we use g_type_class_peek_parent()
here instead of making our own copy?
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.
Since derived classes hold a reference count on their parent classes as long as they are instantiated, the returned class will always exist.
Always is a very strong assertion, and we do the same for class_init, so I don't see why not.
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.
Ah but peek_parent isn't right.
This code copies the type data of the interface into the type data of the class that implements the interface. https://docs.gtk.org/gobject/concepts.html#interface-initialization
We get a pointer to the interface class type in this method. It will be valid as long as instances of the interface exist. So we should be able to just take this pointer and use it in the TypeData.
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.
But this is our version of the interface struct, with the changes applied by our type. Not the default/parent one, which is currently saved away
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 but I only took a short look now :) I'll check again tomorrow or Monday.
1eacb86
to
a431d87
Compare
Alright, that apparently also needs an addition to |
Also a good thing to make more consistent between interfaces and classes I guess :) For classes I used those associated types elsewhere in the past too so it might also become useful for something else. |
Maybe it makes sense to handle this separately. Interfaces can also inherit from other interfaces, so we can't just assume GTypeInterface. We'd also need access to the public type, so I guess |
This makes ObjectInterface and ObjectSubclass more similar to each other and allows for cleaner separation between unsafe ffi code and application implementation.
Is that so? 🤯 I thought that worked differently via the prerequisites. I'm fine with keeping this for a separate PR in any case. Don't have to do everything at once. |
a431d87
to
60ffeec
Compare
You are right. I stared at GType for too long. |
But now I'm wondering if that could actually be made to work 🤣 |
@felinira Should we get this in then or do you want to change more as part of this PR? The boxed copy of the struct and the simple generic interface struct can also be done separately, don't really have to entangle it all and this here is IMHO complete and good as it is. |
I won't mind getting this in now. I opened #1389 to track the remaining bits. |
Let's do that then :) |
This makes ObjectInterface and ObjectSubclass more similar to each other and allows for cleaner separation between the unsafe ffi code and rust implementation.
There is some bikeshedding left to be done:
InterfaceClassStruct
is quite clumsy, but reusingClassStruct
is not possible, as it is tailored towards object subclasses. We could call itInterfaceStruct
to align it withIsClass
->IsInterface
and similar traits that omitClass
. Then we should also nameObjectInterface::Class
ObjectInterface::Interface
I suppose.Do we need something like
glib::subclass::basic::ClassStruct
forInterfaceClassStruct
? I would say we don't, as most interfaces define vfuncs anyway.Closes #1382