Skip to main content

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}