1 // Take a look at the license at the top of the repository in the LICENSE file. 2 3 //! `IMPL` The `wrapper!` macro and miscellaneous wrapper traits. 4 5 /// Defines a wrapper type and implements the appropriate traits. 6 /// 7 /// The basic syntax is 8 /// 9 /// ```ignore 10 /// wrapper! { 11 /// /// Your documentation goes here 12 /// pub struct $name($kind<$foreign>); 13 /// 14 /// match fn { 15 /// $fn_name => /* a closure-like expression */, 16 /// ... 17 /// } 18 /// } 19 /// ``` 20 /// 21 /// This creates a wrapper named `$name` around the foreign type 22 /// `$foreign` of `$kind` — one of [`Boxed`][#boxed], 23 /// [`Shared`][#shared], or [`Object`][#object]. 24 /// 25 /// Inside the `match fn` block there are closure-like expressions to 26 /// provide ways of copying/freeing, or referencing/unreferencing the 27 /// value that you are wrapping. These expressions will be evaluated 28 /// in an `unsafe` context, since they frequently invoke `extern` 29 /// functions from an FFI crate. 30 /// 31 /// What follows is a description of each of the possible `$kind`: 32 /// [`Boxed`][#boxed], [`Shared`][#shared], and [`Object`][#object]; 33 /// note that each supports different sets of `$fn_name` inside the 34 /// `match fn` block. Also, `Object` may require you to specify 35 /// things like the class struct to wrap, plus any interfaces that the 36 /// class implements. 37 /// 38 /// ### Boxed 39 /// 40 /// Boxed records with single ownership. 41 /// 42 /// With no registered `glib_ffi::GType`: 43 /// 44 /// ```ignore 45 /// wrapper! { 46 /// /// Text buffer iterator 47 /// pub struct TextIter(Boxed<ffi::GtkTextIter>); 48 /// 49 /// match fn { 50 /// copy => |ptr| ffi::gtk_text_iter_copy(ptr), 51 /// free => |ptr| ffi::gtk_text_iter_free(ptr), 52 /// } 53 /// } 54 /// ``` 55 /// 56 /// `copy`: `|*const $foreign| -> *mut $foreign` creates a copy of the value. 57 /// 58 /// `free`: `|*mut $foreign|` frees the value. 59 /// 60 /// With a registered `glib_ffi::GType`: 61 /// 62 /// ```ignore 63 /// wrapper! { 64 /// /// Text buffer iterator 65 /// pub struct TextIter(Boxed<ffi::GtkTextIter>); 66 /// 67 /// match fn { 68 /// copy => |ptr| ffi::gtk_text_iter_copy(ptr), 69 /// free => |ptr| ffi::gtk_text_iter_free(ptr), 70 /// type_ => || ffi::gtk_text_iter_get_type(), 71 /// } 72 /// } 73 /// ``` 74 /// 75 /// `type_`: `|| -> glib_ffi::GType` (optional) returns the 76 /// `glib_ffi::GType` that corresponds to the foreign struct. 77 /// 78 /// ### Shared 79 /// 80 /// Records with reference-counted, shared ownership. 81 /// 82 /// With no registered `glib_ffi::GType`: 83 /// 84 /// ```ignore 85 /// wrapper! { 86 /// /// Object holding timing information for a single frame. 87 /// pub struct FrameTimings(Shared<ffi::GdkFrameTimings>); 88 /// 89 /// match fn { 90 /// ref => |ptr| ffi::gdk_frame_timings_ref(ptr), 91 /// unref => |ptr| ffi::gdk_frame_timings_unref(ptr), 92 /// } 93 /// } 94 /// ``` 95 /// 96 /// `ref`: `|*mut $foreign|` increases the refcount. 97 /// 98 /// `unref`: `|*mut $foreign|` decreases the refcount. 99 /// 100 /// With a registered `glib_ffi::GType`: 101 /// 102 /// ```ignore 103 /// wrapper! { 104 /// /// Object holding timing information for a single frame. 105 /// pub struct FrameTimings(Shared<ffi::GdkFrameTimings>); 106 /// 107 /// match fn { 108 /// ref => |ptr| ffi::gdk_frame_timings_ref(ptr), 109 /// unref => |ptr| ffi::gdk_frame_timings_unref(ptr), 110 /// type_ => || ffi::gdk_frame_timings_get_type(), 111 /// } 112 /// } 113 /// ``` 114 /// 115 /// `type_`: `|| -> glib_ffi::GType` (optional) returns the 116 /// `glib_ffi::GType` that corresponds to the foreign struct. 117 /// 118 /// ### Object 119 /// 120 /// Objects -- classes. Note that the class name, if available, must be specified after the 121 /// $foreign type; see below for [non-derivable classes][#non-derivable-classes]. 122 /// 123 /// The basic syntax is this: 124 /// 125 /// ```ignore 126 /// wrapper! { 127 /// /// Your documentation goes here 128 /// pub struct InstanceName(Object<ffi::InstanceStruct, ffi::ClassStruct>) 129 /// @extends ParentClass, GrandparentClass, ..., 130 /// @implements Interface1, Interface2, ...; 131 /// 132 /// match fn { 133 /// type_ => || ffi::instance_get_type(), 134 /// } 135 /// } 136 /// ``` 137 /// 138 /// `type_`: `|| -> glib_ffi::GType` returns the `glib_ffi::GType` 139 /// that corresponds to the foreign class. 140 /// 141 /// #### All parent classes must be specified 142 /// 143 /// In the example above, "`@extends ParentClass, GrandparentClass, ...,`" is where you must 144 /// specify all the parent classes of the one you are wrapping. The uppermost parent class, 145 /// `glib::Object`, must not be specified. 146 /// 147 /// For example, `ffi::GtkWindowGroup` derives directly from 148 /// `GObject`, so it can be simply wrapped as follows: 149 /// 150 /// ```ignore 151 /// wrapper! { 152 /// pub struct WindowGroup(Object<ffi::GtkWindowGroup, ffi::GtkWindowGroupClass>); 153 /// 154 /// match fn { 155 /// type_ => || ffi::gtk_window_group_get_type(), 156 /// } 157 /// } 158 /// ``` 159 /// 160 /// In contrast, `ffi::GtkButton` has a parent, grandparent, etc. classes, which must be specified: 161 /// 162 /// ```ignore 163 /// wrapper! { 164 /// pub struct Button(Object<ffi::GtkButton>) @extends Bin, Container, Widget; 165 /// // see note on interfaces in the example below 166 /// 167 /// match fn { 168 /// type_ => || ffi::gtk_button_get_type(), 169 /// } 170 /// } 171 /// ``` 172 /// 173 /// #### Objects which implement interfaces 174 /// 175 /// The example above is incomplete, since `ffi::GtkButton` actually implements two interfaces, 176 /// `Buildable` and `Actionable`. In this case, they must be specified after all the parent classes 177 /// behind the `@implements` keyword: 178 /// 179 /// ```ignore 180 /// wrapper! { 181 /// pub struct Button(Object<ffi::GtkButton>) 182 /// @extends Bin, Container, Widget, // parent classes 183 /// @implements Buildable, Actionable; // interfaces 184 /// 185 /// match fn { 186 /// type_ => || ffi::gtk_button_get_type(), 187 /// } 188 /// } 189 /// ``` 190 /// 191 /// #### Non-derivable classes 192 /// 193 /// By convention, GObject implements "final" classes, i.e. those who 194 /// cannot be subclassed, by *not* exposing a public Class struct. 195 /// This way it is not possible to override any methods, as there are 196 /// no `klass.method_name` fields to overwrite. In this case, don't 197 /// specify a FFI class name at all in the `Object<>` part: 198 /// 199 /// ```ignore 200 /// wrapper! { 201 /// pub struct Clipboard(Object<ffi::GtkClipboard>); 202 /// ... 203 /// } 204 /// ``` 205 /// 206 /// #### Interfaces 207 /// 208 /// Interfaces are passed in the same way to the macro but instead of specifying 209 /// `Object`, `Interface` has to be specified: 210 /// 211 /// ```ignore 212 /// wrapper! { 213 /// pub struct TreeModel(Interface<ffi::GtkTreeModel, ffi::GtkTreeModelIface>); 214 /// ... 215 /// } 216 /// ``` 217 /// 218 /// #### Interfaces with prerequisites 219 /// 220 /// Interfaces can declare prerequisites, i.e. the classes from which types that implement the 221 /// interface have to inherit or interfaces that have to be implemented: 222 /// 223 /// ```ignore 224 /// wrapper! { 225 /// pub struct TreeSortable(Interface<ffi::GtkTreeSortable, ffi::GtkTreeSortable>) @requires TreeModel; 226 /// ... 227 /// } 228 /// ``` 229 /// 230 /// [#boxed]: #boxed 231 /// [#shared]: #shared 232 /// [#object]: #object 233 /// [#non-derivable-classes]: #non-derivable-classes 234 235 #[macro_export] 236 macro_rules! wrapper { 237 // Boxed 238 239 ( 240 $(#[$attr:meta])* 241 pub struct $name:ident(Boxed<$ffi_name:ty>); 242 243 match fn { 244 copy => |$copy_arg:ident| $copy_expr:expr, 245 free => |$free_arg:ident| $free_expr:expr, 246 } 247 ) => { 248 $crate::glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr, 249 @free $free_arg $free_expr); 250 }; 251 252 ( 253 $(#[$attr:meta])* 254 pub struct $name:ident(Boxed<$ffi_name:ty>); 255 256 match fn { 257 copy => |$copy_arg:ident| $copy_expr:expr, 258 free => |$free_arg:ident| $free_expr:expr, 259 type_ => || $get_type_expr:expr, 260 } 261 ) => { 262 $crate::glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr, 263 @free $free_arg $free_expr, @type_ $get_type_expr); 264 }; 265 266 ( 267 $(#[$attr:meta])* 268 pub struct $name:ident(Boxed<$ffi_name:ty>); 269 270 match fn { 271 copy => |$copy_arg:ident| $copy_expr:expr, 272 free => |$free_arg:ident| $free_expr:expr, 273 init => |$init_arg:ident| $init_expr:expr, 274 clear => |$clear_arg:ident| $clear_expr:expr, 275 } 276 ) => { 277 $crate::glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr, 278 @free $free_arg $free_expr, @init $init_arg $init_expr, @clear $clear_arg $clear_expr); 279 }; 280 281 ( 282 $(#[$attr:meta])* 283 pub struct $name:ident(Boxed<$ffi_name:ty>); 284 285 match fn { 286 copy => |$copy_arg:ident| $copy_expr:expr, 287 free => |$free_arg:ident| $free_expr:expr, 288 init => |$init_arg:ident| $init_expr:expr, 289 clear => |$clear_arg:ident| $clear_expr:expr, 290 type_ => || $get_type_expr:expr, 291 } 292 ) => { 293 $crate::glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr, 294 @free $free_arg $free_expr, @init $init_arg $init_expr, @clear $clear_arg $clear_expr, 295 @type_ $get_type_expr); 296 }; 297 298 // Shared 299 300 ( 301 $(#[$attr:meta])* 302 pub struct $name:ident(Shared<$ffi_name:ty>); 303 304 match fn { 305 ref => |$ref_arg:ident| $ref_expr:expr, 306 unref => |$unref_arg:ident| $unref_expr:expr, 307 } 308 ) => { 309 $crate::glib_shared_wrapper!([$($attr)*] $name, $ffi_name, @ref $ref_arg $ref_expr, 310 @unref $unref_arg $unref_expr); 311 }; 312 313 ( 314 $(#[$attr:meta])* 315 pub struct $name:ident(Shared<$ffi_name:ty>); 316 317 match fn { 318 ref => |$ref_arg:ident| $ref_expr:expr, 319 unref => |$unref_arg:ident| $unref_expr:expr, 320 type_ => || $get_type_expr:expr, 321 } 322 ) => { 323 $crate::glib_shared_wrapper!([$($attr)*] $name, $ffi_name, @ref $ref_arg $ref_expr, 324 @unref $unref_arg $unref_expr, @type_ $get_type_expr); 325 }; 326 327 // Object, no class struct, no parents or interfaces 328 ( 329 $(#[$attr:meta])* 330 pub struct $name:ident(Object<$ffi_name:ty>); 331 332 match fn { 333 type_ => || $get_type_expr:expr, 334 } 335 ) => { 336 $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, std::os::raw::c_void, @type_ $get_type_expr, @extends [], @implements []); 337 }; 338 339 // Object, class struct, no parents or interfaces 340 ( 341 $(#[$attr:meta])* 342 pub struct $name:ident(Object<$ffi_name:ty, $ffi_class_name:ty>); 343 344 match fn { 345 type_ => || $get_type_expr:expr, 346 } 347 ) => { 348 $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, @type_ $get_type_expr, @extends [], @implements []); 349 }; 350 351 // Object, no class struct, parents, no interfaces 352 ( 353 $(#[$attr:meta])* 354 pub struct $name:ident(Object<$ffi_name:ty>) @extends $($extends:path),+; 355 356 match fn { 357 type_ => || $get_type_expr:expr, 358 } 359 ) => { 360 $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, std::os::raw::c_void, 361 @type_ $get_type_expr, @extends [$($extends),+], @implements []); 362 }; 363 364 // Object, class struct, parents, no interfaces 365 ( 366 $(#[$attr:meta])* 367 pub struct $name:ident(Object<$ffi_name:ty, $ffi_class_name:ty>) @extends $($extends:path),+; 368 369 match fn { 370 type_ => || $get_type_expr:expr, 371 } 372 ) => { 373 $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, 374 @type_ $get_type_expr, @extends [$($extends),+], @implements []); 375 }; 376 377 // Object, no class struct, no parents, interfaces 378 ( 379 $(#[$attr:meta])* 380 pub struct $name:ident(Object<$ffi_name:ty>) @implements $($implements:path),+; 381 382 match fn { 383 type_ => || $get_type_expr:expr, 384 } 385 ) => { 386 $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, std::os::raw::c_void, 387 @type_ $get_type_expr, @extends [], @implements [$($implements),+]); 388 }; 389 390 // Object, class struct, no parents, interfaces 391 ( 392 $(#[$attr:meta])* 393 pub struct $name:ident(Object<$ffi_name:ty, $ffi_class_name:ty>) @implements $($implements:path),+; 394 395 match fn { 396 type_ => || $get_type_expr:expr, 397 } 398 ) => { 399 $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, 400 @type_ $get_type_expr, @extends [], @implements [$($implements),+]); 401 }; 402 403 // Object, no class struct, parents and interfaces 404 ( 405 $(#[$attr:meta])* 406 pub struct $name:ident(Object<$ffi_name:ty>) @extends $($extends:path),+, @implements $($implements:path),+; 407 408 match fn { 409 type_ => || $get_type_expr:expr, 410 } 411 ) => { 412 $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, std::os::raw::c_void, 413 @type_ $get_type_expr, @extends [$($extends),+], @implements [$($implements),+]); 414 }; 415 416 // Object, class struct, parents and interfaces 417 ( 418 $(#[$attr:meta])* 419 pub struct $name:ident(Object<$ffi_name:ty, $ffi_class_name:ty>) @extends $($extends:path),+, @implements $($implements:path),+; 420 421 match fn { 422 type_ => || $get_type_expr:expr, 423 } 424 ) => { 425 $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, 426 @type_ $get_type_expr, @extends [$($extends),+], @implements [$($implements),+]); 427 }; 428 429 // ObjectSubclass, no parents or interfaces 430 ( 431 $(#[$attr:meta])* 432 pub struct $name:ident(ObjectSubclass<$subclass:ty>); 433 ) => { 434 $crate::glib_object_wrapper!(@object [$($attr)*] $name, <$subclass as $crate::subclass::types::ObjectSubclass>::Instance, <$subclass as $crate::subclass::types::ObjectSubclass>::Class, 435 @type_ $crate::translate::IntoGlib::into_glib(<$subclass as $crate::subclass::types::ObjectSubclassType>::type_()), 436 @extends [], @implements []); 437 unsafe impl $crate::object::ObjectSubclassIs for $name { 438 type Subclass = $subclass; 439 } 440 }; 441 442 // ObjectSubclass, no parents, interfaces 443 ( 444 $(#[$attr:meta])* 445 pub struct $name:ident(ObjectSubclass<$subclass:ty>) @implements $($implements:path),+; 446 ) => { 447 $crate::glib_object_wrapper!(@object [$($attr)*] $name, <$subclass as $crate::subclass::types::ObjectSubclass>::Instance, <$subclass as $crate::subclass::types::ObjectSubclass>::Class, 448 @type_ $crate::translate::IntoGlib::into_glib(<$subclass as $crate::subclass::types::ObjectSubclassType>::type_()), 449 @extends [], @implements [$($implements),+]); 450 unsafe impl $crate::object::ObjectSubclassIs for $name { 451 type Subclass = $subclass; 452 } 453 }; 454 455 // ObjectSubclass, parents, no interfaces 456 ( 457 $(#[$attr:meta])* 458 pub struct $name:ident(ObjectSubclass<$subclass:ty>) @extends $($extends:path),+; 459 ) => { 460 $crate::glib_object_wrapper!(@object [$($attr)*] $name, <$subclass as $crate::subclass::types::ObjectSubclass>::Instance, <$subclass as $crate::subclass::types::ObjectSubclass>::Class, 461 @type_ $crate::translate::IntoGlib::into_glib(<$subclass as $crate::subclass::types::ObjectSubclassType>::type_()), 462 @extends [$($extends),+], @implements []); 463 unsafe impl $crate::object::ObjectSubclassIs for $name { 464 type Subclass = $subclass; 465 } 466 }; 467 468 // ObjectSubclass, parents and interfaces 469 ( 470 $(#[$attr:meta])* 471 pub struct $name:ident(ObjectSubclass<$subclass:ty>) @extends $($extends:path),+, @implements $($implements:path),+; 472 ) => { 473 $crate::glib_object_wrapper!(@object [$($attr)*] $name, <$subclass as $crate::subclass::types::ObjectSubclass>::Instance, <$subclass as $crate::subclass::types::ObjectSubclass>::Class, 474 @type_ $crate::translate::IntoGlib::into_glib(<$subclass as $crate::subclass::types::ObjectSubclassType>::type_()), 475 @extends [$($extends),+], @implements [$($implements),+]); 476 unsafe impl $crate::object::ObjectSubclassIs for $name { 477 type Subclass = $subclass; 478 } 479 }; 480 481 // Interface, no prerequisites, no class 482 ( 483 $(#[$attr:meta])* 484 pub struct $name:ident(Interface<$ffi_name:ty>); 485 486 match fn { 487 type_ => || $get_type_expr:expr, 488 } 489 ) => { 490 $crate::glib_object_wrapper!(@interface [$($attr)*] $name, $ffi_name, std::os::raw::c_void, @type_ $get_type_expr, @requires []); 491 }; 492 493 // Interface, prerequisites, no class 494 ( 495 $(#[$attr:meta])* 496 pub struct $name:ident(Interface<$ffi_name:ty>) @requires $($requires:path),+; 497 498 match fn { 499 type_ => || $get_type_expr:expr, 500 } 501 ) => { 502 $crate::glib_object_wrapper!(@interface [$($attr)*] $name, $ffi_name, std::os::raw::c_void, @type_ $get_type_expr, @requires [$($requires),+]); 503 }; 504 505 // Interface, no prerequisites, class 506 ( 507 $(#[$attr:meta])* 508 pub struct $name:ident(Interface<$ffi_name:ty, $ffi_class_name:ty>); 509 510 match fn { 511 type_ => || $get_type_expr:expr, 512 } 513 ) => { 514 $crate::glib_object_wrapper!(@interface [$($attr)*] $name, $ffi_name, $ffi_class_name, @type_ $get_type_expr, @requires []); 515 }; 516 517 // Interface, prerequisites, class 518 ( 519 $(#[$attr:meta])* 520 pub struct $name:ident(Interface<$ffi_name:ty, $ffi_class_name:ty>) @requires $($requires:path),+; 521 522 match fn { 523 type_ => || $get_type_expr:expr, 524 } 525 ) => { 526 $crate::glib_object_wrapper!(@interface [$($attr)*] $name, $ffi_name, $ffi_class_name, @type_ $get_type_expr, @requires [$($requires),+]); 527 }; 528 529 // ObjectInterface, no prerequisites 530 ( 531 $(#[$attr:meta])* 532 pub struct $name:ident(ObjectInterface<$iface_name:ty>); 533 ) => { 534 $crate::glib_object_wrapper!(@interface [$($attr)*] $name, std::os::raw::c_void, $iface_name, 535 @type_ $crate::translate::IntoGlib::into_glib(<$iface_name as $crate::subclass::interface::ObjectInterfaceType>::type_()), 536 @requires []); 537 }; 538 539 // ObjectInterface, prerequisites 540 ( 541 $(#[$attr:meta])* 542 pub struct $name:ident(ObjectInterface<$iface_name:ty>) @requires $($requires:path),+; 543 ) => { 544 $crate::glib_object_wrapper!(@interface [$($attr)*] $name, std::os::raw::c_void, $iface_name, 545 @type_ $crate::translate::IntoGlib::into_glib(<$iface_name as $crate::subclass::interface::ObjectInterfaceType>::type_()), 546 @requires [$($requires),+]); 547 }; 548 } 549