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