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