1
- /// Public part of the BaseButton
1
+ /// Public API of ` BaseButton`.
2
2
mod imp;
3
3
4
- pub use self :: imp:: PinnedFuture ;
5
4
use gtk:: {
6
5
glib:: { self , subclass:: prelude:: * } ,
7
6
prelude:: * ,
8
7
subclass:: prelude:: * ,
9
8
} ;
9
+ use std:: { future:: Future , pin:: Pin } ;
10
+
11
+ /// Type alias for pinned boxed futures that output `T`.
12
+ pub type PinnedFuture < T > = Pin < Box < dyn Future < Output = T > > > ;
10
13
11
14
glib:: wrapper! {
15
+ /// Public type for the `BaseButton` instances.
12
16
pub struct BaseButton ( ObjectSubclass <imp:: BaseButton >)
13
17
@extends gtk:: Widget , gtk:: Button ;
14
18
}
15
19
16
20
impl BaseButton {
21
+ /// Creates a new instance of `BaseButton`.
17
22
pub fn new ( ) -> Self {
18
23
glib:: Object :: new ( )
19
24
}
@@ -25,84 +30,136 @@ impl Default for BaseButton {
25
30
}
26
31
}
27
32
28
- /// Public trait that implements our functions for everything that derives from BaseButton
29
- pub trait BaseButtonExt {
30
- fn sync_method ( & self , extra_text : Option < String > ) ;
31
- fn async_method ( & self ) -> PinnedFuture ;
32
- }
33
+ /// Public trait that implements our functions for everything that derives from `BaseButton`.
34
+ ///
35
+ /// These are public methods that can be called on any instance.
36
+ pub trait BaseButtonExt : IsA < BaseButton > {
37
+ /// Caller for a non-virtual method on `BaseButton`.
38
+ ///
39
+ /// This directly calls the method inside the implementation module.
40
+ fn non_virtual_method ( & self ) {
41
+ self . upcast_ref :: < BaseButton > ( ) . imp ( ) . non_virtual_method ( ) ;
42
+ }
33
43
34
- /// We call into imp::BaseButton_$method_name for each function. These will retrieve the
35
- /// correct class (the base class for the BaseButton or the derived class for DerivedButton)
36
- /// and call the correct implementation of the function.
37
- impl < O : IsA < BaseButton > > BaseButtonExt for O {
38
- fn sync_method ( & self , extra_text : Option < String > ) {
39
- imp :: base_button_sync_method ( self . upcast_ref :: < BaseButton > ( ) , extra_text)
44
+ /// Caller for a virtual method on `BaseButton`.
45
+ ///
46
+ /// This retrieves this instance's class and calls the function pointer in it .
47
+ fn sync_method ( & self , extra_text : Option < & str > ) {
48
+ let obj = self . upcast_ref :: < BaseButton > ( ) ;
49
+ ( obj . class ( ) . as_ref ( ) . sync_method ) ( obj , extra_text) ;
40
50
}
41
51
42
- fn async_method ( & self ) -> PinnedFuture {
43
- imp:: base_button_async_method ( self . upcast_ref :: < BaseButton > ( ) )
52
+ /// Caller for an async virtual method on `BaseButton`.
53
+ ///
54
+ /// This retrieves this instance's class and calls the function pointer in it.
55
+ ///
56
+ /// Once async functions in traits are supported this should become one.
57
+ fn async_method ( & self ) -> PinnedFuture < Result < ( ) , glib:: Error > > {
58
+ let obj = self . upcast_ref :: < BaseButton > ( ) ;
59
+ ( obj. class ( ) . as_ref ( ) . async_method ) ( obj)
44
60
}
45
61
}
46
62
47
- /// The BaseButtonImpl that each derived private struct has to implement. See derived_button/imp.rs for how
48
- /// to override functions.
49
- pub trait BaseButtonImpl : ButtonImpl + ObjectImpl + ' static {
50
- fn sync_method ( & self , obj : & BaseButton , extra_text : Option < String > ) {
51
- self . parent_sync_method ( obj, extra_text)
63
+ impl < O : IsA < BaseButton > > BaseButtonExt for O { }
64
+
65
+ /// The `BaseButtonImpl` trait that each derived implementation struct has to implement.
66
+ ///
67
+ /// See `derived_button/imp.rs` for how to override virtual methods.
68
+ pub trait BaseButtonImpl : ButtonImpl {
69
+ /// Default implementation of a virtual method.
70
+ ///
71
+ /// This always calls into the implementation of the parent class so that if the subclass does
72
+ /// not explicitly implement it, the behaviour of its parent class will be preserved.
73
+ fn sync_method ( & self , extra_text : Option < & str > ) {
74
+ self . parent_sync_method ( extra_text)
52
75
}
53
76
54
- fn async_method ( & self , obj : & BaseButton ) -> PinnedFuture {
55
- self . parent_async_method ( obj)
77
+ /// Default implementation of an async virtual method.
78
+ ///
79
+ /// This always calls into the implementation of the parent class so that if the subclass does
80
+ /// not explicitly implement it, the behaviour of its parent class will be preserved.
81
+ fn async_method ( & self ) -> PinnedFuture < Result < ( ) , glib:: Error > > {
82
+ self . parent_async_method ( )
56
83
}
57
84
}
58
85
59
- pub trait BaseButtonImplExt : ObjectSubclass {
60
- fn parent_sync_method ( & self , obj : & BaseButton , extra_text : Option < String > ) ;
61
- fn parent_async_method ( & self , obj : & BaseButton ) -> PinnedFuture ;
62
- }
63
-
64
- impl < T : BaseButtonImpl > BaseButtonImplExt for T {
65
- fn parent_sync_method ( & self , obj : & BaseButton , extra_text : Option < String > ) {
86
+ /// Public trait with "protected" methods for everything implementing `BaseButton`.
87
+ ///
88
+ /// These are supposed to be called only from inside implementations of `BaseButton` subclasses.
89
+ pub trait BaseButtonImplExt : BaseButtonImpl {
90
+ /// Retrieves the parent class' implementation of the virtual method and calls it.
91
+ fn parent_sync_method ( & self , extra_text : Option < & str > ) {
66
92
unsafe {
67
93
let data = Self :: type_data ( ) ;
68
- let parent_class = & * ( data. as_ref ( ) . parent_class ( ) as * mut imp :: BaseButtonClass ) ;
69
- ( parent_class. sync_method ) ( obj, extra_text)
94
+ let parent_class = & * ( data. as_ref ( ) . parent_class ( ) as * mut Class ) ;
95
+ ( parent_class. sync_method ) ( self . obj ( ) . unsafe_cast_ref ( ) , extra_text)
70
96
}
71
97
}
72
98
73
- fn parent_async_method ( & self , obj : & BaseButton ) -> PinnedFuture {
99
+ /// Retrieves the parent class' implementation of the async virtual method and calls it.
100
+ fn parent_async_method ( & self ) -> PinnedFuture < Result < ( ) , glib:: Error > > {
74
101
unsafe {
75
102
let data = Self :: type_data ( ) ;
76
- let parent_class = & * ( data. as_ref ( ) . parent_class ( ) as * mut imp :: BaseButtonClass ) ;
77
- ( parent_class. async_method ) ( obj)
103
+ let parent_class = & * ( data. as_ref ( ) . parent_class ( ) as * mut Class ) ;
104
+ ( parent_class. async_method ) ( self . obj ( ) . unsafe_cast_ref ( ) )
78
105
}
79
106
}
80
107
}
81
108
82
- /// Make the BaseButton subclassable
109
+ impl < T : BaseButtonImpl > BaseButtonImplExt for T { }
110
+
111
+ /// This allows to implement subclasses of `BaseButton`.
83
112
unsafe impl < T : BaseButtonImpl > IsSubclassable < T > for BaseButton {
113
+ /// Called whenever the class of a `BaseButton` subclass is initialized, i.e. usually right
114
+ /// before the first instance of it is created.
84
115
fn class_init ( class : & mut glib:: Class < Self > ) {
85
116
Self :: parent_class_init :: < T > ( class. upcast_ref_mut ( ) ) ;
86
117
118
+ // Override the virtual method function pointers to call directly into the `BaseButtonImpl`
119
+ // of the subclass.
120
+ //
121
+ // Note that this is only called for actual subclasses and not `BaseButton` itself:
122
+ // `BaseButton` does not implement `BaseButtonImpl` and handles this inside
123
+ // `ObjectSubclass::class_init()` for providing the default implementation of the virtual
124
+ // methods.
87
125
let klass = class. as_mut ( ) ;
88
- klass. sync_method = sync_method_trampoline :: < T > ;
89
- klass. async_method = async_method_trampoline :: < T > ;
126
+ klass. sync_method = |obj, extra_text| unsafe {
127
+ let imp = obj. unsafe_cast_ref :: < T :: Type > ( ) . imp ( ) ;
128
+ imp. sync_method ( extra_text)
129
+ } ;
130
+ klass. async_method = |obj| unsafe {
131
+ let imp = obj. unsafe_cast_ref :: < T :: Type > ( ) . imp ( ) ;
132
+ imp. async_method ( )
133
+ } ;
90
134
}
91
135
}
92
136
93
- // Virtual method implementation trampolines
94
- fn sync_method_trampoline < T > ( this : & BaseButton , extra_text : Option < String > )
95
- where
96
- T : ObjectSubclass + BaseButtonImpl ,
97
- {
98
- let imp = this. dynamic_cast_ref :: < T :: Type > ( ) . unwrap ( ) . imp ( ) ;
99
- imp. sync_method ( this, extra_text)
137
+ /// GObject class struct with the function pointers for the virtual methods.
138
+ ///
139
+ /// This must be `#[repr(C)]`.
140
+ #[ repr( C ) ]
141
+ pub struct Class {
142
+ pub parent_class : gtk:: ffi:: GtkButtonClass ,
143
+
144
+ // If these functions are meant to be called from C, you need to make these functions
145
+ // `unsafe extern "C" fn` & use FFI-safe types (usually raw pointers).
146
+ pub sync_method : fn ( & BaseButton , extra_text : Option < & str > ) ,
147
+ pub async_method : fn ( & BaseButton ) -> PinnedFuture < Result < ( ) , glib:: Error > > ,
148
+ }
149
+
150
+ /// Make it possible to use this struct as class struct in an `ObjectSubclass` trait
151
+ /// implementation.
152
+ ///
153
+ /// This is `unsafe` to enforce that the struct is `#[repr(C)]`.
154
+ unsafe impl ClassStruct for Class {
155
+ type Type = imp:: BaseButton ;
100
156
}
101
157
102
- fn async_method_trampoline < T > ( this : & BaseButton ) -> PinnedFuture
103
- where
104
- T : ObjectSubclass + BaseButtonImpl ,
105
- {
106
- let imp = this. dynamic_cast_ref :: < T :: Type > ( ) . unwrap ( ) . imp ( ) ;
107
- imp. async_method ( this)
158
+ /// Deref directly to the parent class' class struct.
159
+ impl std:: ops:: Deref for Class {
160
+ type Target = glib:: Class < <<Self as ClassStruct >:: Type as ObjectSubclass >:: ParentType > ;
161
+
162
+ fn deref ( & self ) -> & Self :: Target {
163
+ unsafe { & * ( & self . parent_class as * const _ as * const _ ) }
164
+ }
108
165
}
0 commit comments