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 = ();