-
-
Notifications
You must be signed in to change notification settings - Fork 115
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
add support of module types #1169
Conversation
d08dff6
to
5266273
Compare
This would fix #55, or would something still be missing? |
glib/src/gobject/auto/type_module.rs
Outdated
} | ||
|
||
#[doc(alias = "g_type_module_register_enum")] | ||
fn register_enum(&self, name: &str, const_static_values: &EnumValue) -> crate::types::Type { |
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 add()
/ register()
API here, would it make more sense to hide that behind a macro? E.g. the glib::Enum
macro with some additional configuration?
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 you are right. Honestly I did not do it because I don't need it in my project. I will try to add it...
glib/src/gobject/auto/type_plugin.rs
Outdated
|
||
pub trait TypePluginExt: IsA<TypePlugin> + sealed::Sealed + 'static { | ||
#[doc(alias = "g_type_plugin_complete_interface_info")] | ||
fn complete_interface_info( |
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.
And also this maybe as part of a macro instead of proper public API?
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 PR focuses more on TypeModule
than on TypePlugin
. I added TypePlugin
and TypePluginExt
only because GTypeModule
implements GTypePlugin
in Glib and I generated the code from GIR files.
I tried to respect the behavior of the TypeModule
(according to Glib documentation) in the new macros and i suppose TypePlugin
has a different behavior (e.g. it does not define load
and unload
virtual functions) so I don't really now how to deal with it... And I don't need that since GTypeModule
already implements it.
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.
What I mean is that this PR adds quite a bit of public API that should probably never be called by user code but only by the macro, so maybe it can be moved directly into the macro instead and call the FFI API there.
TypePlugin
/ TypeModule` and their ext traits with the (useful) public API should still exists of course.
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 currently working on a new implementation of the macros to support TypePlugin
as well. I have to finalize it (fix comments and add tests) but I hope I will push a new commit next week. However I won't have so much time for the 2 next weeks, so I will do my best. Stay tuned...
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.
here it is (see 22ab846).
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 have changed implementation of macros in order to use static dispatch and avoid dynamic dispatch (see 0fe707d)
glib/src/gobject/interface_info.rs
Outdated
wrapper! { | ||
#[derive(Debug)] | ||
#[doc(alias = "GInterfaceInfo")] | ||
pub struct InterfaceInfo(BoxedInline<gobject_ffi::GInterfaceInfo>); |
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 this has no GType
assigned and also otherwise no memory management functions, maybe this should be implemented fully manually? There's no point in ever cloning these, for example, is there? So it could just be a &
reference returned from the functions
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.
(same for the other two types here)
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.
Do you have some examples to help me understand how to do it ?
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'd define a
#[repr(transparent)]
pub struct InterfaceInfo(gobject_ffi::GInterfaceInfo);
and then can do things like
let ptr: *const gobject_ffi::GInterfaceInfo;
let info: &InterfaceInfo = &*(ptr as *const InterfaceInfo);
As there's no memory management associated with these structs in C, inventing that on the bindings side is going to be problematic.
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.
New commit c484822 to change the implementation.
As TypePlugin
and TypeModule
are generated by gir
tool, they require InterfaceInfo
, TypeInfo
and TypeValueTable
to implement function from_glib_ptr_borrow_mut
and trait ToGlibPtr
.
I don't know how to tell gir
to not use these functions.
Therefore I decided to implement the missing functions and missing trait (ToGlibPtr
) and also implement other complementary traits (IntoGlib
, FromGlib
, ToGlibPtrMut
, FromGlibPtrNone
) which imo is more coherent.
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't have ToGlibPtr::to_glib_full()
for these and also not FromGlibPtrNone
and IntoGlib
and FromGlib
. Those implementations conceptually make no sense.
For the time being you will have to implement the functions with these types manually to get the correct behaviour (borrowing).
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 is very basic infrastructure so it's quite expected that gir won't do the right thing here and manual bindings are needed in many places.
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 have removed implementation of traits and I have made manual bindings so now code of TypePlugin
and TypeModule
is manual and not generated anymore. See commit d631c13
TypeValueTable, | ||
}; | ||
|
||
pub trait TypePluginImpl: ObjectImpl + TypePluginImplExt { |
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.
Can you add a minimal test for this too?
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 will try, but again I added TypePlugin
types only because I wanted to respect how GTypeModule
is implemented in Glib (by implementing the GTypePugin
interface)
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.
done (see 22ab846).
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.
Generally looks good to me but I don't really know the dynamic type API of GObject :)
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.
Seems mostly fine to me now. If this is the best API design for this will have to be figured out by someone actually using it, but it works for now apparently :)
glib/src/gobject/type_info.rs
Outdated
#[derive(Debug)] | ||
#[doc(alias = "GTypeInfo")] | ||
#[repr(transparent)] | ||
pub struct TypeInfo(pub gobject_ffi::GTypeInfo); |
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 struct TypeInfo(pub gobject_ffi::GTypeInfo); | |
pub struct TypeInfo(pub(crate) gobject_ffi::GTypeInfo); |
Maybe, plus an as_ptr()
function that returns the underlying FFI pointer?
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.
Done (see f1eac51). Also added from_glib_ptr_borrow_mut
.
glib/src/subclass/type_plugin.rs
Outdated
fn parent_complete_type_info( | ||
&self, | ||
type_: Type, | ||
info: &mut TypeInfo, |
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.
Why does this have to be mutable? There's nothing we (can) change in it, is there?
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, according to Glib documentation GObject.TypePlugin.complete_type_info implementations of the interface must fill info
.
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.
How would they fill that currently?
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.
complete_type_info
is usually called by the Glib type system. A rust implementation of TypePlugin
could be something like:
pub struct MyPlugin {
my_type_type_info: Cell<glib::TypeInfo>,
...
}
impl TypePluginImpl for MyPlugin {
....
fn complete_type_info(&self, type_: glib::Type, info: &mut glib::TypeInfo, value_table: &mut glib::TypeValueTable) {
match self.my_type_type_info.get() {
Some(my_type_info) => *info = my_type_info,
_ => panic!("unexpected"),
}
}
...
}
impl MyPlugin {
fn register_dynamic_type(&self, parent_type: glib::Type, type_name: &str, type_info: &glib::TypeInfo, flags: glib::TypeFlags) -> glib::Type {
let type_ = unsafe {
glib::Type::from_glib(glib::gobject_ffi::g_type_register_dynamic(parent_type.into_glib(), type_name.as_ptr(), self.obj().upcast_ref::<glib::TypePlugin>().as_ptr(), flags.into_glib()))
};
if type_.is_valid() {
self.my_type_type_info.set(Some(*type_info));
}
type_
}
}
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.
that sounds like this vfunc should be returning (glib::TypeInfo, glib::TypeValueTable)
then
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.
My question was more how an implementation in Rust would even create or modify a TypeInfo
right now. But I see, that makes sense for future extensibility then.
Is the TypeInfo
passed in by GObject here already correctly initialized, or is the implementer supposed to return a new one? That would basically be what decides if the mutable references or the return tuple is the right choice.
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 finally changed it to return a tuple (see 22ab846).
glib/src/gobject/type_plugin.rs
Outdated
&self, | ||
g_type: crate::types::Type, | ||
info: &mut TypeInfo, | ||
value_table: &mut TypeValueTable, |
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.
Why are these two mutable? (also in the other places)
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.
Same for value_table
.
Also same for info
within implementations of GObject.TypePlugin.complete_interface_info.
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 finally changed it to return a tuple (see 22ab846).
glib/src/gobject/type_value_table.rs
Outdated
#[derive(Debug)] | ||
#[doc(alias = "GTypeValueTable")] | ||
#[repr(transparent)] | ||
pub struct TypeValueTable(pub gobject_ffi::GTypeValueTable); |
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 struct TypeValueTable(pub gobject_ffi::GTypeValueTable); | |
pub struct TypeValueTable(pub(crate) gobject_ffi::GTypeValueTable); |
maybe
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.
Done (see f1eac51). Also added as_ptr
and from_glib_ptr_borrow_mut
.
@@ -3,4 +3,24 @@ | |||
#[derive(Debug)] | |||
#[doc(alias = "GInterfaceInfo")] | |||
#[repr(transparent)] | |||
pub struct InterfaceInfo(pub gobject_ffi::GInterfaceInfo); | |||
pub struct InterfaceInfo(pub(crate) gobject_ffi::GInterfaceInfo); |
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 struct InterfaceInfo(pub(crate) gobject_ffi::GInterfaceInfo); | |
pub struct InterfaceInfo(gobject_ffi::GInterfaceInfo); |
as you would be from_glib_ptr_borrow_mut to construct them anyway, right?
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.
No, some code needs to create instance of InterfaceInfo
and similar types: see in glib/src/subclass/types.rs
Or maybe I can add a new
method ?
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.
Seems fine to me like this, but a constructor pub(crate)
would also work and reduce the code a bit
7eb9cbb
to
0fe707d
Compare
glib/src/gobject/type_module.rs
Outdated
impl fmt::Display for TypeModule { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
f.write_str("TypeModule") | ||
} | ||
} |
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 remove all those Display implementations, we have dropped them in the main branch
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.
done
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 otherwise, thanks!
This PR does not support dynamic registration of |
fix some bugs |
Seems fine in a separate PR. |
glib/src/subclass/type_plugin.rs
Outdated
let type_name = CString::new(type_name).unwrap(); | ||
let mut g_type = gobject_ffi::g_type_from_name(type_name.as_ptr()); |
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 type_name = CString::new(type_name).unwrap(); | |
let mut g_type = gobject_ffi::g_type_from_name(type_name.as_ptr()); | |
let mut g_type = gobject_ffi::g_type_from_name(type_name.to_glib_none().0); |
or
let type_name = CString::new(type_name).unwrap(); | |
let mut g_type = gobject_ffi::g_type_from_name(type_name.as_ptr()); | |
let mut g_type = type_name.run_with_gstr(|type_name| gobject_ffi::g_type_from_name(type_name.as_ptr())); |
also elsewhere
glib/src/subclass/mod.rs
Outdated
//! } | ||
//! | ||
//! fn register_dynamic_type(&self, parent_type: glib::Type, type_name: &str, type_info: &glib::TypeInfo, flags: glib::TypeFlags) -> glib::Type { | ||
//! let type_ = 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 wonder if there wouldn't be some more convenient (even if unsafe
) API that wouldn't require user code to do FFI directly.
g_type_from_name()
for example has safe wrappers, g_type_register_dynamic()
should be possible to wrap in something a bit more convenient at least (taking non-FFI types, taking care of the C string conversion, ...)
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 indeed. I have added Type::get_plugin()
, Type::register_dynamic()
and Type::add_interface_dynamic()
wrappers and code is now concise and clearer.
Once this is ready, please also squash it all into fewer commits that are each one functional and useful change (i.e. in your case I guess a single commit) |
ecfe5fe
to
d945d12
Compare
About enums and flags, I have removed the piece of code that was introduced early with this PR (essentially due to the generation of code). It will be part of a separate PR. |
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.
One last thing, otherwise this is IMHO ready. @bilelmoussaoui ?
glib/src/types.rs
Outdated
@@ -223,6 +223,48 @@ impl Type { | |||
} | |||
} | |||
|
|||
#[doc(alias = "g_type_get_plugin")] | |||
pub fn get_plugin(self) -> Option<TypePlugin> { |
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 fn get_plugin(self) -> Option<TypePlugin> { | |
pub fn plugin(self) -> Option<TypePlugin> { |
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.
done
d945d12
to
35d7226
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.
otherwise lgtm, thanks
glib/src/subclass/interface.rs
Outdated
@@ -3,25 +3,28 @@ | |||
use std::{marker, mem}; | |||
|
|||
use super::{InitializingType, Signal}; | |||
use crate::{prelude::*, translate::*, Object, ParamSpec, Type}; | |||
use crate::{ | |||
gobject::traits::DynamicObjectRegisterExt, prelude::*, translate::*, Object, ParamSpec, Type, |
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.
gobject::traits::DynamicObjectRegisterExt, prelude::*, translate::*, Object, ParamSpec, Type, | |
prelude::*, translate::*, Object, ParamSpec, Type, |
glib's prelude should include gobject's one
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.
done
35d7226
to
7497a1b
Compare
… types Signed-off-by: fbrouille <[email protected]>
This PR aims to add support of module types and interfaces. See https://docs.gtk.org/gobject/class.TypeModule.html
The new macros
module_object_subclass
andmodule_object_interface
allow to register types and interfaces that are part of a module (e.g. a shared library on linux). The macros mimicobject_subclass
andobject_interface
but generate code that support registration when the module (TypeModule
) is loaded, following the behavior defined in Glib doc. However it is possible to postpone the registration at first use of the type (like forobject_subclass
) by explicitly setting the macro attributelazy_registration = true
.Some examples in
glib-macros/tests/test.rs
,glib/src/subclass/mod.rs
andglib/src/subclass/type_module.rs