1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | // rustdoc-stripper-ignore-next |
4 | //! `IMPL` The `wrapper!` macro and miscellaneous wrapper traits. |
5 | |
6 | // rustdoc-stripper-ignore-next |
7 | /// Defines a wrapper type and implements the appropriate traits. |
8 | /// |
9 | /// The basic syntax is |
10 | /// |
11 | /// ```ignore |
12 | /// wrapper! { |
13 | /// /// Your documentation goes here |
14 | /// pub struct $name($kind<$foreign>); |
15 | /// |
16 | /// match fn { |
17 | /// $fn_name => /* a closure-like expression */, |
18 | /// ... |
19 | /// } |
20 | /// } |
21 | /// ``` |
22 | /// |
23 | /// This creates a wrapper named `$name` around the foreign type |
24 | /// `$foreign` of `$kind` — one of [`Boxed`][#boxed], |
25 | /// [`Shared`][#shared], or [`Object`][#object]. |
26 | /// |
27 | /// Inside the `match fn` block there are closure-like expressions to |
28 | /// provide ways of copying/freeing, or referencing/unreferencing the |
29 | /// value that you are wrapping. These expressions will be evaluated |
30 | /// in an `unsafe` context, since they frequently invoke `extern` |
31 | /// functions from an FFI crate. |
32 | /// |
33 | /// What follows is a description of each of the possible `$kind`: |
34 | /// [`Boxed`][#boxed], [`Shared`][#shared], and [`Object`][#object]; |
35 | /// note that each supports different sets of `$fn_name` inside the |
36 | /// `match fn` block. Also, `Object` may require you to specify |
37 | /// things like the class struct to wrap, plus any interfaces that the |
38 | /// class implements. |
39 | /// |
40 | /// ### Boxed (heap allocated) |
41 | /// |
42 | /// Boxed records with single ownership allocated on the heap. |
43 | /// |
44 | /// With no registered `glib_ffi::GType`: |
45 | /// |
46 | /// ```ignore |
47 | /// wrapper! { |
48 | /// /// Text buffer iterator |
49 | /// pub struct TextIter(Boxed<ffi::GtkTextIter>); |
50 | /// |
51 | /// match fn { |
52 | /// copy => |ptr| ffi::gtk_text_iter_copy(ptr), |
53 | /// free => |ptr| ffi::gtk_text_iter_free(ptr), |
54 | /// } |
55 | /// } |
56 | /// ``` |
57 | /// |
58 | /// `copy`: `|*const $foreign| -> *mut $foreign` creates a copy of the value. |
59 | /// |
60 | /// `free`: `|*mut $foreign|` frees the value. |
61 | /// |
62 | /// With a registered `glib_ffi::GType`: |
63 | /// |
64 | /// ```ignore |
65 | /// wrapper! { |
66 | /// /// Text buffer iterator |
67 | /// pub struct TextIter(Boxed<ffi::GtkTextIter>); |
68 | /// |
69 | /// match fn { |
70 | /// copy => |ptr| ffi::gtk_text_iter_copy(ptr), |
71 | /// free => |ptr| ffi::gtk_text_iter_free(ptr), |
72 | /// type_ => || ffi::gtk_text_iter_get_type(), |
73 | /// } |
74 | /// } |
75 | /// ``` |
76 | /// |
77 | /// `type_`: `|| -> glib_ffi::GType` (optional) returns the |
78 | /// `glib_ffi::GType` that corresponds to the foreign struct. |
79 | /// |
80 | /// ### BoxedInline (inline, stack allocated) |
81 | /// |
82 | /// Boxed records with single ownership allocated on the stack or otherwise inline. |
83 | /// With no registered `glib_ffi::GType`: |
84 | /// |
85 | /// ```ignore |
86 | /// wrapper! { |
87 | /// /// Text buffer iterator |
88 | /// pub struct TextIter(BoxedInline<ffi::GtkTextIter>); |
89 | /// |
90 | /// match fn { |
91 | /// copy => |ptr| ffi::gtk_text_iter_copy(ptr), |
92 | /// free => |ptr| ffi::gtk_text_iter_free(ptr), |
93 | /// } |
94 | /// } |
95 | /// ``` |
96 | /// |
97 | /// `copy`: `|*const $foreign| -> *mut $foreign` (optional) creates a heap allocated copy of the value. |
98 | /// |
99 | /// `free`: `|*mut $foreign|` (optional) frees the value. |
100 | /// |
101 | /// With a registered `glib_ffi::GType`: |
102 | /// |
103 | /// ```ignore |
104 | /// wrapper! { |
105 | /// /// Text buffer iterator |
106 | /// pub struct TextIter(BoxedInline<ffi::GtkTextIter>); |
107 | /// |
108 | /// match fn { |
109 | /// copy => |ptr| ffi::gtk_text_iter_copy(ptr), |
110 | /// free => |ptr| ffi::gtk_text_iter_free(ptr), |
111 | /// type_ => || ffi::gtk_text_iter_get_type(), |
112 | /// } |
113 | /// } |
114 | /// ``` |
115 | /// |
116 | /// `type_`: `|| -> glib_ffi::GType` (optional) returns the |
117 | /// `glib_ffi::GType` that corresponds to the foreign struct. |
118 | /// |
119 | /// ### Shared |
120 | /// |
121 | /// Records with reference-counted, shared ownership. |
122 | /// |
123 | /// With no registered `glib_ffi::GType`: |
124 | /// |
125 | /// ```ignore |
126 | /// wrapper! { |
127 | /// /// Object holding timing information for a single frame. |
128 | /// pub struct FrameTimings(Shared<ffi::GdkFrameTimings>); |
129 | /// |
130 | /// match fn { |
131 | /// ref => |ptr| ffi::gdk_frame_timings_ref(ptr), |
132 | /// unref => |ptr| ffi::gdk_frame_timings_unref(ptr), |
133 | /// } |
134 | /// } |
135 | /// ``` |
136 | /// |
137 | /// `ref`: `|*mut $foreign|` increases the refcount. |
138 | /// |
139 | /// `unref`: `|*mut $foreign|` decreases the refcount. |
140 | /// |
141 | /// With a registered `glib_ffi::GType`: |
142 | /// |
143 | /// ```ignore |
144 | /// wrapper! { |
145 | /// /// Object holding timing information for a single frame. |
146 | /// pub struct FrameTimings(Shared<ffi::GdkFrameTimings>); |
147 | /// |
148 | /// match fn { |
149 | /// ref => |ptr| ffi::gdk_frame_timings_ref(ptr), |
150 | /// unref => |ptr| ffi::gdk_frame_timings_unref(ptr), |
151 | /// type_ => || ffi::gdk_frame_timings_get_type(), |
152 | /// } |
153 | /// } |
154 | /// ``` |
155 | /// |
156 | /// `type_`: `|| -> glib_ffi::GType` (optional) returns the |
157 | /// `glib_ffi::GType` that corresponds to the foreign struct. |
158 | /// |
159 | /// ### Object |
160 | /// |
161 | /// Objects -- classes. Note that the class name, if available, must be specified after the |
162 | /// $foreign type; see below for [non-derivable classes][#non-derivable-classes]. |
163 | /// |
164 | /// The basic syntax is this: |
165 | /// |
166 | /// ```ignore |
167 | /// wrapper! { |
168 | /// /// Your documentation goes here |
169 | /// pub struct InstanceName(Object<ffi::InstanceStruct, ffi::ClassStruct>) |
170 | /// @extends ParentClass, GrandparentClass, ..., |
171 | /// @implements Interface1, Interface2, ...; |
172 | /// |
173 | /// match fn { |
174 | /// type_ => || ffi::instance_get_type(), |
175 | /// } |
176 | /// } |
177 | /// ``` |
178 | /// |
179 | /// `type_`: `|| -> glib_ffi::GType` returns the `glib_ffi::GType` |
180 | /// that corresponds to the foreign class. |
181 | /// |
182 | /// #### All parent classes must be specified |
183 | /// |
184 | /// In the example above, "`@extends ParentClass, GrandparentClass, ...,`" is where you must |
185 | /// specify all the parent classes of the one you are wrapping. The uppermost parent class, |
186 | /// `glib::Object`, must not be specified. |
187 | /// |
188 | /// For example, `ffi::GtkWindowGroup` derives directly from |
189 | /// `GObject`, so it can be simply wrapped as follows: |
190 | /// |
191 | /// ```ignore |
192 | /// wrapper! { |
193 | /// pub struct WindowGroup(Object<ffi::GtkWindowGroup, ffi::GtkWindowGroupClass>); |
194 | /// |
195 | /// match fn { |
196 | /// type_ => || ffi::gtk_window_group_get_type(), |
197 | /// } |
198 | /// } |
199 | /// ``` |
200 | /// |
201 | /// In contrast, `ffi::GtkButton` has a parent, grandparent, etc. classes, which must be specified: |
202 | /// |
203 | /// ```ignore |
204 | /// wrapper! { |
205 | /// pub struct Button(Object<ffi::GtkButton>) @extends Bin, Container, Widget; |
206 | /// // see note on interfaces in the example below |
207 | /// |
208 | /// match fn { |
209 | /// type_ => || ffi::gtk_button_get_type(), |
210 | /// } |
211 | /// } |
212 | /// ``` |
213 | /// |
214 | /// #### Objects which implement interfaces |
215 | /// |
216 | /// The example above is incomplete, since `ffi::GtkButton` actually implements two interfaces, |
217 | /// `Buildable` and `Actionable`. In this case, they must be specified after all the parent classes |
218 | /// behind the `@implements` keyword: |
219 | /// |
220 | /// ```ignore |
221 | /// wrapper! { |
222 | /// pub struct Button(Object<ffi::GtkButton>) |
223 | /// @extends Bin, Container, Widget, // parent classes |
224 | /// @implements Buildable, Actionable; // interfaces |
225 | /// |
226 | /// match fn { |
227 | /// type_ => || ffi::gtk_button_get_type(), |
228 | /// } |
229 | /// } |
230 | /// ``` |
231 | /// |
232 | /// #### Non-derivable classes |
233 | /// |
234 | /// By convention, GObject implements "final" classes, i.e. those who |
235 | /// cannot be subclassed, by *not* exposing a public Class struct. |
236 | /// This way it is not possible to override any methods, as there are |
237 | /// no `klass.method_name` fields to overwrite. In this case, don't |
238 | /// specify a FFI class name at all in the `Object<>` part: |
239 | /// |
240 | /// ```ignore |
241 | /// wrapper! { |
242 | /// pub struct Clipboard(Object<ffi::GtkClipboard>); |
243 | /// ... |
244 | /// } |
245 | /// ``` |
246 | /// |
247 | /// #### Interfaces |
248 | /// |
249 | /// Interfaces are passed in the same way to the macro but instead of specifying |
250 | /// `Object`, `Interface` has to be specified: |
251 | /// |
252 | /// ```ignore |
253 | /// wrapper! { |
254 | /// pub struct TreeModel(Interface<ffi::GtkTreeModel, ffi::GtkTreeModelIface>); |
255 | /// ... |
256 | /// } |
257 | /// ``` |
258 | /// |
259 | /// #### Interfaces with prerequisites |
260 | /// |
261 | /// Interfaces can declare prerequisites, i.e. the classes from which types that implement the |
262 | /// interface have to inherit or interfaces that have to be implemented: |
263 | /// |
264 | /// ```ignore |
265 | /// wrapper! { |
266 | /// pub struct TreeSortable(Interface<ffi::GtkTreeSortable, ffi::GtkTreeSortable>) @requires TreeModel; |
267 | /// ... |
268 | /// } |
269 | /// ``` |
270 | /// |
271 | /// [#boxed]: #boxed |
272 | /// [#shared]: #shared |
273 | /// [#object]: #object |
274 | /// [#non-derivable-classes]: #non-derivable-classes |
275 | |
276 | #[macro_export ] |
277 | macro_rules! wrapper { |
278 | // Boxed |
279 | ( |
280 | $(#[$attr:meta])* |
281 | $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Boxed<$ffi_name:ty>); |
282 | |
283 | match fn { |
284 | copy => |$copy_arg:ident| $copy_expr:expr, |
285 | free => |$free_arg:ident| $free_expr:expr, |
286 | $( |
287 | type_ => || $get_type_expr:expr, |
288 | )? |
289 | } |
290 | ) => { |
291 | $crate::glib_boxed_wrapper!( |
292 | [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, |
293 | @copy $copy_arg $copy_expr, @free $free_arg $free_expr |
294 | $(, @type_ $get_type_expr)? |
295 | ); |
296 | }; |
297 | |
298 | // BoxedInline |
299 | ( |
300 | $(#[$attr:meta])* |
301 | $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (BoxedInline<$ffi_name:ty>); |
302 | |
303 | match fn { |
304 | $( |
305 | copy => |$copy_arg:ident| $copy_expr:expr, |
306 | free => |$free_arg:ident| $free_expr:expr, |
307 | )? |
308 | $( |
309 | init => |$init_arg:ident| $init_expr:expr, |
310 | copy_into => |$copy_into_arg_dest:ident, $copy_into_arg_src:ident| $copy_into_expr:expr, |
311 | clear => |$clear_arg:ident| $clear_expr:expr, |
312 | )? |
313 | $( |
314 | type_ => || $get_type_expr:expr, |
315 | )? |
316 | } |
317 | ) => { |
318 | $crate::glib_boxed_inline_wrapper!( |
319 | [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name |
320 | $(, @copy $copy_arg $copy_expr, @free $free_arg $free_expr)? |
321 | $(, @init $init_arg $init_expr, @copy_into $copy_into_arg_dest $copy_into_arg_src $copy_into_expr, @clear $clear_arg $clear_expr)? |
322 | $(, @type_ $get_type_expr)? |
323 | ); |
324 | }; |
325 | |
326 | // BoxedInline |
327 | ( |
328 | $(#[$attr:meta])* |
329 | $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (BoxedInline<$ffi_name:ty>); |
330 | ) => { |
331 | $crate::glib_boxed_inline_wrapper!( |
332 | [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name |
333 | ); |
334 | }; |
335 | |
336 | // Shared |
337 | ( |
338 | $(#[$attr:meta])* |
339 | $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Shared<$ffi_name:ty>); |
340 | |
341 | match fn { |
342 | ref => |$ref_arg:ident| $ref_expr:expr, |
343 | unref => |$unref_arg:ident| $unref_expr:expr, |
344 | $( |
345 | type_ => || $get_type_expr:expr, |
346 | )? |
347 | } |
348 | ) => { |
349 | $crate::glib_shared_wrapper!( |
350 | [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, |
351 | @ref $ref_arg $ref_expr, @unref $unref_arg $unref_expr |
352 | $(, @type_ $get_type_expr)? |
353 | ); |
354 | }; |
355 | |
356 | // Object, no parents |
357 | ( |
358 | $(#[$attr:meta])* |
359 | $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Object<$ffi_name:ty $(, $ffi_class_name:ty)?>) $(@implements $($implements:path),+)?; |
360 | |
361 | match fn { |
362 | type_ => || $get_type_expr:expr, |
363 | } |
364 | ) => { |
365 | $crate::glib_object_wrapper!( |
366 | @object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, (), $ffi_name, |
367 | $( @ffi_class $ffi_class_name ,)? |
368 | @type_ $get_type_expr, |
369 | @extends [], |
370 | @implements [$($($implements),+)?] |
371 | ); |
372 | }; |
373 | |
374 | // Object, parents |
375 | ( |
376 | $(#[$attr:meta])* |
377 | $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Object<$ffi_name:ty $(, $ffi_class_name:ty)?>) @extends $($extends:path),+ $(, @implements $($implements:path),+)?; |
378 | |
379 | match fn { |
380 | type_ => || $get_type_expr:expr, |
381 | } |
382 | ) => { |
383 | $crate::glib_object_wrapper!( |
384 | @object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, (), $ffi_name, |
385 | $( @ffi_class $ffi_class_name ,)? |
386 | @type_ $get_type_expr, |
387 | @extends [$($extends),+], |
388 | @implements [$($($implements),+)?] |
389 | ); |
390 | }; |
391 | |
392 | // ObjectSubclass, no parents |
393 | ( |
394 | $(#[$attr:meta])* |
395 | $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (ObjectSubclass<$subclass:ty>) $(@implements $($implements:path),+)?; |
396 | ) => { |
397 | $crate::glib_object_wrapper!( |
398 | @object_subclass [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $subclass, |
399 | @extends [], |
400 | @implements [$($($implements),+)?] |
401 | ); |
402 | }; |
403 | |
404 | // ObjectSubclass, parents |
405 | ( |
406 | $(#[$attr:meta])* |
407 | $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (ObjectSubclass<$subclass:ty>) @extends $($extends:path),+ $(, @implements $($implements:path),+)?; |
408 | ) => { |
409 | $crate::glib_object_wrapper!( |
410 | @object_subclass [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $subclass, |
411 | @extends [$($extends),+], |
412 | @implements [$($($implements),+)?] |
413 | ); |
414 | }; |
415 | |
416 | // Interface |
417 | ( |
418 | $(#[$attr:meta])* |
419 | $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Interface<$ffi_name:ty $(, $ffi_class_name:ty)?>) $(@requires $($requires:path),+)?; |
420 | |
421 | match fn { |
422 | type_ => || $get_type_expr:expr, |
423 | } |
424 | ) => { |
425 | $crate::glib_object_wrapper!( |
426 | @interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, $ffi_name, |
427 | $( @ffi_class $ffi_class_name ,)? |
428 | @type_ $get_type_expr, |
429 | @requires [$( $($requires),+ )?] |
430 | ); |
431 | }; |
432 | |
433 | // ObjectInterface |
434 | ( |
435 | $(#[$attr:meta])* |
436 | $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (ObjectInterface<$iface_name:ty>) $(@requires $($requires:path),+)?; |
437 | ) => { |
438 | $crate::glib_object_wrapper!( |
439 | @interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, std::os::raw::c_void, |
440 | @ffi_class $iface_name, |
441 | @type_ $crate::translate::IntoGlib::into_glib(<$iface_name as $crate::subclass::interface::ObjectInterfaceType>::type_()), |
442 | @requires [$( $($requires),+ )?] |
443 | ); |
444 | }; |
445 | } |
446 | |