glib/
wrapper.rs

1// Copyright 2015-2016, The Gtk-rs Project Developers.
2// See the COPYRIGHT file at the top-level directory of this distribution.
3// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4
5//! `IMPL` The `glib_wrapper!` macro and miscellaneous wrapper traits.
6
7/// Defines a wrapper type and implements the appropriate traits.
8///
9/// The basic syntax is
10///
11/// ```ignore
12/// glib_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
41///
42/// Boxed records with single ownership.
43///
44/// With no registered `glib_ffi::GType`:
45///
46/// ```ignore
47/// glib_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/// glib_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///         get_type => ||    ffi::gtk_text_iter_get_type(),
73///     }
74/// }
75/// ```
76///
77/// `get_type`: `|| -> glib_ffi::GType` (optional) returns the
78/// `glib_ffi::GType` that corresponds to the foreign struct.
79///
80/// ### Shared
81///
82/// Records with reference-counted, shared ownership.
83///
84/// With no registered `glib_ffi::GType`:
85///
86/// ```ignore
87/// glib_wrapper! {
88///     /// Object holding timing information for a single frame.
89///     pub struct FrameTimings(Shared<ffi::GdkFrameTimings>);
90///
91///     match fn {
92///         ref   => |ptr| ffi::gdk_frame_timings_ref(ptr),
93///         unref => |ptr| ffi::gdk_frame_timings_unref(ptr),
94///     }
95/// }
96/// ```
97///
98/// `ref`: `|*mut $foreign|` increases the refcount.
99///
100/// `unref`: `|*mut $foreign|` decreases the refcount.
101///
102/// With a registered `glib_ffi::GType`:
103///
104/// ```ignore
105/// glib_wrapper! {
106///     /// Object holding timing information for a single frame.
107///     pub struct FrameTimings(Shared<ffi::GdkFrameTimings>);
108///
109///     match fn {
110///         ref      => |ptr| ffi::gdk_frame_timings_ref(ptr),
111///         unref    => |ptr| ffi::gdk_frame_timings_unref(ptr),
112///         get_type => ||    ffi::gdk_frame_timings_get_type(),
113///     }
114/// }
115/// ```
116///
117/// `get_type`: `|| -> glib_ffi::GType` (optional) returns the
118/// `glib_ffi::GType` that corresponds to the foreign struct.
119///
120/// ### Object
121///
122/// Objects -- classes.  Note that the class name, if available, must be specified after the
123/// $foreign type; see below for [non-derivable classes][#non-derivable-classes].
124///
125/// The basic syntax is this:
126///
127/// ```ignore
128/// glib_wrapper! {
129///     /// Your documentation goes here
130///     pub struct InstanceName(Object<ffi::InstanceStruct, ffi::ClassStruct, ClassName>)
131///         @extends ParentClass, GrandparentClass, ...,
132///         @implements Interface1, Interface2, ...;
133///
134///     match fn {
135///         get_type => || ffi::instance_get_type(),
136///     }
137/// }
138/// ```
139///
140/// `get_type`: `|| -> glib_ffi::GType` returns the `glib_ffi::GType`
141/// that corresponds to the foreign class.
142///
143/// #### All parent classes must be specified
144///
145/// In the example above, "`@extends ParentClass, GrandparentClass, ...,`" is where you must
146/// specify all the parent classes of the one you are wrapping. The uppermost parent class,
147/// `glib::Object`, must not be specified.
148///
149/// For example, `ffi::GtkWindowGroup` derives directly from
150/// `GObject`, so it can be simply wrapped as follows:
151///
152/// ```ignore
153/// glib_wrapper! {
154///     pub struct WindowGroup(Object<ffi::GtkWindowGroup, ffi::GtkWindowGroupClass, WindowGroupClass>);
155///
156///     match fn {
157///         get_type => || ffi::gtk_window_group_get_type(),
158///     }
159/// }
160/// ```
161///
162/// In contrast, `ffi::GtkButton` has a parent, grandparent, etc. classes, which must be specified:
163///
164/// ```ignore
165/// glib_wrapper! {
166///     pub struct Button(Object<ffi::GtkButton, ButtonClass>) @extends Bin, Container, Widget;
167///         // see note on interfaces in the example below
168///
169///     match fn {
170///         get_type => || ffi::gtk_button_get_type(),
171///     }
172/// }
173/// ```
174///
175/// #### Objects which implement interfaces
176///
177/// The example above is incomplete, since `ffi::GtkButton` actually implements two interfaces,
178/// `Buildable` and `Actionable`.  In this case, they must be specified after all the parent classes
179/// behind the `@implements` keyword:
180///
181/// ```ignore
182/// glib_wrapper! {
183///     pub struct Button(Object<ffi::GtkButton, ButtonClass>)
184///         @extends Bin, Container, Widget, // parent classes
185///         @implements Buildable, Actionable;  // interfaces
186///
187///     match fn {
188///         get_type => || ffi::gtk_button_get_type(),
189///     }
190/// }
191/// ```
192///
193/// #### Non-derivable classes
194///
195/// By convention, GObject implements "final" classes, i.e. those who
196/// cannot be subclassed, by *not* exposing a public Class struct.
197/// This way it is not possible to override any methods, as there are
198/// no `klass.method_name` fields to overwrite.  In this case, don't
199/// specify a FFI class name at all in the `Object<>` part:
200///
201/// ```ignore
202/// glib_wrapper! {
203///     pub struct Clipboard(Object<ffi::GtkClipboard, ClipboardClass>);
204///     ...
205/// }
206/// ```
207///
208/// #### Interfaces
209///
210/// Interfaces are passed in the same way to the macro but instead of specifying
211/// `Object`, `Interface` has to be specified:
212///
213/// ```ignore
214/// glib_wrapper! {
215///     pub struct TreeModel(Interface<ffi::GtkTreeModel, ffi::GtkTreeModelIface, TreeModelIface>);
216///     ...
217/// }
218/// ```
219///
220/// #### Interfaces with prerequisites
221///
222/// Interfaces can declare prerequisites, i.e. the classes from which types that implement the
223/// interface have to inherit or interfaces that have to be implemented:
224///
225/// ```ignore
226/// glib_wrapper! {
227///     pub struct TreeSortable(Interface<ffi::GtkTreeSortable, ffi::GtkTreeSortable, TreeSortableIface>) @requires TreeModel;
228///     ...
229/// }
230/// ```
231///
232/// [#boxed]: #boxed
233/// [#shared]: #shared
234/// [#object]: #object
235/// [#non-derivable-classes]: #non-derivable-classes
236
237#[macro_export]
238macro_rules! glib_wrapper {
239    // Boxed
240
241    (
242        $(#[$attr:meta])*
243        pub struct $name:ident(Boxed<$ffi_name:path>);
244
245        match fn {
246            copy => |$copy_arg:ident| $copy_expr:expr,
247            free => |$free_arg:ident| $free_expr:expr,
248        }
249    ) => {
250        $crate::glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr,
251            @free $free_arg $free_expr);
252    };
253
254    (
255        $(#[$attr:meta])*
256        pub struct $name:ident(Boxed<$ffi_name:path>);
257
258        match fn {
259            copy => |$copy_arg:ident| $copy_expr:expr,
260            free => |$free_arg:ident| $free_expr:expr,
261            get_type => || $get_type_expr:expr,
262        }
263    ) => {
264        $crate::glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr,
265            @free $free_arg $free_expr, @get_type $get_type_expr);
266    };
267
268    (
269        $(#[$attr:meta])*
270        pub struct $name:ident(Boxed<$ffi_name:path>);
271
272        match fn {
273            copy => |$copy_arg:ident| $copy_expr:expr,
274            free => |$free_arg:ident| $free_expr:expr,
275            init => |$init_arg:ident| $init_expr:expr,
276            clear => |$clear_arg:ident| $clear_expr:expr,
277        }
278    ) => {
279        $crate::glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr,
280            @free $free_arg $free_expr, @init $init_arg $init_expr, @clear $clear_arg $clear_expr);
281    };
282
283    (
284        $(#[$attr:meta])*
285        pub struct $name:ident(Boxed<$ffi_name:path>);
286
287        match fn {
288            copy => |$copy_arg:ident| $copy_expr:expr,
289            free => |$free_arg:ident| $free_expr:expr,
290            init => |$init_arg:ident| $init_expr:expr,
291            clear => |$clear_arg:ident| $clear_expr:expr,
292            get_type => || $get_type_expr:expr,
293        }
294    ) => {
295        $crate::glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr,
296            @free $free_arg $free_expr, @init $init_arg $init_expr, @clear $clear_arg $clear_expr,
297            @get_type $get_type_expr);
298    };
299
300    // Shared
301
302    (
303        $(#[$attr:meta])*
304        pub struct $name:ident(Shared<$ffi_name:path>);
305
306        match fn {
307            ref => |$ref_arg:ident| $ref_expr:expr,
308            unref => |$unref_arg:ident| $unref_expr:expr,
309        }
310    ) => {
311        $crate::glib_shared_wrapper!([$($attr)*] $name, $ffi_name, @ref $ref_arg $ref_expr,
312            @unref $unref_arg $unref_expr);
313    };
314
315    (
316        $(#[$attr:meta])*
317        pub struct $name:ident(Shared<$ffi_name:path>);
318
319        match fn {
320            ref => |$ref_arg:ident| $ref_expr:expr,
321            unref => |$unref_arg:ident| $unref_expr:expr,
322            get_type => || $get_type_expr:expr,
323        }
324    ) => {
325        $crate::glib_shared_wrapper!([$($attr)*] $name, $ffi_name, @ref $ref_arg $ref_expr,
326            @unref $unref_arg $unref_expr, @get_type $get_type_expr);
327    };
328
329    // Object, no class struct, no parents or interfaces
330    (
331        $(#[$attr:meta])*
332        pub struct $name:ident(Object<$ffi_name:path, $rust_class_name:ident>);
333
334        match fn {
335            get_type => || $get_type_expr:expr,
336        }
337    ) => {
338        $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $crate::wrapper::Void, $rust_class_name, @get_type $get_type_expr, @extends [], @implements []);
339    };
340
341    // Object, class struct, no parents or interfaces
342    (
343        $(#[$attr:meta])*
344        pub struct $name:ident(Object<$ffi_name:path, $ffi_class_name:path, $rust_class_name:ident>);
345
346        match fn {
347            get_type => || $get_type_expr:expr,
348        }
349    ) => {
350        $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, $rust_class_name, @get_type $get_type_expr, @extends [], @implements []);
351    };
352
353    // Object, no class struct, parents, no interfaces
354    (
355        $(#[$attr:meta])*
356        pub struct $name:ident(Object<$ffi_name:path, $rust_class_name:ident>) @extends $($extends:path),+;
357
358        match fn {
359            get_type => || $get_type_expr:expr,
360        }
361    ) => {
362        $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $crate::wrapper::Void, $rust_class_name,
363            @get_type $get_type_expr, @extends [$($extends),+], @implements []);
364    };
365
366    // Object, class struct, parents, no interfaces
367    (
368        $(#[$attr:meta])*
369        pub struct $name:ident(Object<$ffi_name:path, $ffi_class_name:path, $rust_class_name:ident>) @extends $($extends:path),+;
370
371        match fn {
372            get_type => || $get_type_expr:expr,
373        }
374    ) => {
375        $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, $rust_class_name,
376            @get_type $get_type_expr, @extends [$($extends),+], @implements []);
377    };
378
379    // Object, no class struct, no parents, interfaces
380    (
381        $(#[$attr:meta])*
382        pub struct $name:ident(Object<$ffi_name:path, $rust_class_name:ident>) @implements $($implements:path),+;
383
384        match fn {
385            get_type => || $get_type_expr:expr,
386        }
387    ) => {
388        $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $crate::wrapper::Void, $rust_class_name,
389            @get_type $get_type_expr, @extends [], @implements [$($implements),+]);
390    };
391
392    // Object, class struct, no parents, interfaces
393    (
394        $(#[$attr:meta])*
395        pub struct $name:ident(Object<$ffi_name:path, $ffi_class_name:path, $rust_class_name:ident>) @implements $($implements:path),+;
396
397        match fn {
398            get_type => || $get_type_expr:expr,
399        }
400    ) => {
401        $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, $rust_class_name,
402            @get_type $get_type_expr, @extends [], @implements [$($implements),+]);
403    };
404
405    // Object, no class struct, parents and interfaces
406    (
407        $(#[$attr:meta])*
408        pub struct $name:ident(Object<$ffi_name:path, $rust_class_name:ident>) @extends $($extends:path),+, @implements $($implements:path),+;
409
410        match fn {
411            get_type => || $get_type_expr:expr,
412        }
413    ) => {
414        $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $crate::wrapper::Void, $rust_class_name,
415            @get_type $get_type_expr, @extends [$($extends),+], @implements [$($implements),+]);
416    };
417
418    // Object, class struct, parents and interfaces
419    (
420        $(#[$attr:meta])*
421        pub struct $name:ident(Object<$ffi_name:path, $ffi_class_name:path, $rust_class_name:ident>) @extends $($extends:path),+, @implements $($implements:path),+;
422
423        match fn {
424            get_type => || $get_type_expr:expr,
425        }
426    ) => {
427        $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, $rust_class_name,
428            @get_type $get_type_expr, @extends [$($extends),+], @implements [$($implements),+]);
429    };
430
431    // Interface, no prerequisites
432    (
433        $(#[$attr:meta])*
434        pub struct $name:ident(Interface<$ffi_name:path>);
435
436        match fn {
437            get_type => || $get_type_expr:expr,
438        }
439    ) => {
440        $crate::glib_object_wrapper!(@interface [$($attr)*] $name, $ffi_name, @get_type $get_type_expr, @requires []);
441    };
442
443    // Interface, prerequisites
444    (
445        $(#[$attr:meta])*
446        pub struct $name:ident(Interface<$ffi_name:path>) @requires $($requires:path),+;
447
448        match fn {
449            get_type => || $get_type_expr:expr,
450        }
451    ) => {
452        $crate::glib_object_wrapper!(@interface [$($attr)*] $name, $ffi_name, @get_type $get_type_expr, @requires [$($requires),+]);
453    };
454}
455
456// So we can refer to the empty type by a path
457pub type Void = ();