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], [`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#[macro_export]
276macro_rules! wrapper {
277    // Boxed
278    (
279        $(#[$attr:meta])*
280        $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Boxed<$ffi_name:ty>);
281
282        match fn {
283            copy => |$copy_arg:ident| $copy_expr:expr,
284            free => |$free_arg:ident| $free_expr:expr,
285            $(
286            type_ => || $get_type_expr:expr,
287            )?
288        }
289    ) => {
290        $crate::glib_boxed_wrapper!(
291            [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name,
292            @copy $copy_arg $copy_expr, @free $free_arg $free_expr
293            $(, @type_ $get_type_expr)?
294        );
295    };
296
297    // BoxedInline
298    (
299        $(#[$attr:meta])*
300        $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (BoxedInline<$ffi_name:ty>);
301
302        match fn {
303            $(
304            copy => |$copy_arg:ident| $copy_expr:expr,
305            free => |$free_arg:ident| $free_expr:expr,
306            )?
307            $(
308            init => |$init_arg:ident| $init_expr:expr,
309            copy_into => |$copy_into_arg_dest:ident, $copy_into_arg_src:ident| $copy_into_expr:expr,
310            clear => |$clear_arg:ident| $clear_expr:expr,
311            )?
312            $(
313            type_ => || $get_type_expr:expr,
314            )?
315        }
316    ) => {
317        $crate::glib_boxed_inline_wrapper!(
318            [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name
319            $(, @copy $copy_arg $copy_expr, @free $free_arg $free_expr)?
320            $(, @init $init_arg $init_expr, @copy_into $copy_into_arg_dest $copy_into_arg_src $copy_into_expr, @clear $clear_arg $clear_expr)?
321            $(, @type_ $get_type_expr)?
322        );
323    };
324
325    // BoxedInline
326    (
327        $(#[$attr:meta])*
328        $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (BoxedInline<$ffi_name:ty>);
329    ) => {
330        $crate::glib_boxed_inline_wrapper!(
331            [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name
332        );
333    };
334
335    // Shared
336    (
337        $(#[$attr:meta])*
338        $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Shared<$ffi_name:ty>);
339
340        match fn {
341            ref => |$ref_arg:ident| $ref_expr:expr,
342            unref => |$unref_arg:ident| $unref_expr:expr,
343            $(
344            type_ => || $get_type_expr:expr,
345            )?
346        }
347    ) => {
348        $crate::glib_shared_wrapper!(
349            [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name,
350            @ref $ref_arg $ref_expr, @unref $unref_arg $unref_expr
351            $(, @type_ $get_type_expr)?
352        );
353    };
354
355    // Object, no parents
356    (
357        $(#[$attr:meta])*
358        $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Object<$ffi_name:ty $(, $ffi_class_name:ty)?>) $(@implements $($implements:path),+)?;
359
360        match fn {
361            type_ => || $get_type_expr:expr,
362        }
363    ) => {
364        $crate::glib_object_wrapper!(
365            @object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, (), $ffi_name,
366            $( @ffi_class $ffi_class_name ,)?
367            @type_ $get_type_expr,
368            @extends [],
369            @implements [$($($implements),+)?]
370        );
371    };
372
373    // Object, parents
374    (
375        $(#[$attr:meta])*
376        $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),+)?;
377
378        match fn {
379            type_ => || $get_type_expr:expr,
380        }
381    ) => {
382        $crate::glib_object_wrapper!(
383            @object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, (), $ffi_name,
384            $( @ffi_class $ffi_class_name ,)?
385            @type_ $get_type_expr,
386            @extends [$($extends),+],
387            @implements [$($($implements),+)?]
388        );
389    };
390
391    // ObjectSubclass, no parents
392    (
393        $(#[$attr:meta])*
394        $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (ObjectSubclass<$subclass:ty>) $(@implements $($implements:path),+)?;
395    ) => {
396        $crate::glib_object_wrapper!(
397            @object_subclass [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $subclass,
398            @extends [],
399            @implements [$($($implements),+)?]
400        );
401    };
402
403    // ObjectSubclass, parents
404    (
405        $(#[$attr:meta])*
406        $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (ObjectSubclass<$subclass:ty>) @extends $($extends:path),+ $(, @implements $($implements:path),+)?;
407    ) => {
408        $crate::glib_object_wrapper!(
409            @object_subclass [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $subclass,
410            @extends [$($extends),+],
411            @implements [$($($implements),+)?]
412        );
413    };
414
415    // Interface
416    (
417        $(#[$attr:meta])*
418        $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Interface<$ffi_name:ty $(, $ffi_class_name:ty)?>) $(@requires $($requires:path),+)?;
419
420        match fn {
421            type_ => || $get_type_expr:expr,
422        }
423    ) => {
424        $crate::glib_object_wrapper!(
425            @interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, $ffi_name,
426            $( @ffi_class $ffi_class_name ,)?
427            @type_ $get_type_expr,
428            @requires [$( $($requires),+ )?]
429        );
430    };
431
432    // ObjectInterface
433    (
434        $(#[$attr:meta])*
435        $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (ObjectInterface<$iface_name:ty>) $(@requires $($requires:path),+)?;
436    ) => {
437        $crate::glib_object_wrapper!(
438            @object_interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $iface_name,
439            @type_ $crate::translate::IntoGlib::into_glib(<$iface_name as $crate::subclass::interface::ObjectInterfaceType>::type_()),
440            @requires [$( $($requires),+ )?]
441        );
442    };
443}