1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
/* Copyright (C) 2018 Olivier Goffart <ogoffart@woboq.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/*! This crate implements binding to the Qt API which allow to use QML from a rust application.

    # Example:

    ```
    #[macro_use] extern crate cstr;
    extern crate qmetaobject;

    use qmetaobject::*;

    // The `QObject` custom derive macro allows to expose a class to Qt and QML
    #[derive(QObject,Default)]
    struct Greeter {
        // Specify the base class with the qt_base_class macro
        base: qt_base_class!(trait QObject),
        // Declare `name` as a property usable from Qt
        name: qt_property!(QString; NOTIFY name_changed),
        // Declare a signal
        name_changed: qt_signal!(),
        // And even a slot
        compute_greetings: qt_method!(fn compute_greetings(&self, verb: String) -> QString {
            format!("{} {}", verb, self.name.to_string()).into()
        })
    }

    fn main() {
        // Register the `Greeter` struct to QML
        qml_register_type::<Greeter>(cstr!("Greeter"), 1, 0, cstr!("Greeter"));
        // Create a QML engine from rust
        let mut engine = QmlEngine::new();
    # return; // We can't create a window in the CI
        // (Here the QML code is inline, but one can also load from a file)
        engine.load_data(r#"
            import QtQuick 2.6
            import QtQuick.Window 2.0
            // Import our Rust classes
            import Greeter 1.0

            Window {
                visible: true
                // Instantiate the rust struct
                Greeter {
                    id: greeter;
                    // Set a property
                    name: "World"
                }
                Text {
                    anchors.centerIn: parent
                    // Call a method
                    text: greeter.compute_greetings("hello")
                }
            }
        "#.into());
        engine.exec();
    }
    ```

    # Basic types

    The re-exported crate [`qttypes`] contains binding to the most usefull
    basic types such as [`QString`], [`QVariant`], ...

    You can also simply use rust type `String`, but using QString might avoid unecessary
    conversions in some case.

    # Meta type

    In order to be able to use a type in a signal or method parameter, or as a property type,
    the type need to implement the [QMetaType](qmetatype/trait.QMetaType.html) trait.
    All the method are provided so you can just implement the QMetaType like this:

    ```rust
    # use qmetaobject::QMetaType;
    #[derive(Default, Clone)]
    struct MyPoint(u32, u32);

    impl QMetaType for MyPoint {};
    ```

    With that it is also possible to put the type in a  [`QVariant`]

    # Object pinning

    Once an object that derives from QObject is exposed to C++, it needs to be pinned, and cannot
    be moved in memory.
    Also, since the Qt code can be re-entrant, the object must be placed in a RefCell.
    The [QObjectPinned](struct.QObjectPinned.html) object is used to enforce the pinning.

    If you want to keep pointer to reference, you can use [QPointer](struct.QPointer.html).

    # Threading

    The QML engine only runs in a single thread. And probably all the `QObject`s needs to be living
    in the Qt thread. But you can use the [queued_callback](fn.queued_callback.html) function to
    create callback that can be called from any thread and are going to run in the Qt thread.

    This can be done like so:

    ```
    # extern crate qmetaobject;
    # use qmetaobject::*;
    #[derive(QObject,Default)]
    struct MyAsyncObject {
        base: qt_base_class!(trait QObject),
        result: qt_property!(QString; NOTIFY result_changed),
        result_changed: qt_signal!(),
        recompute_result: qt_method!(fn recompute_result(&self, name: String) {
            let qptr = QPointer::from(&*self);
            let set_value = qmetaobject::queued_callback(move |val: QString| {
                qptr.as_pinned().map(|self_| {
                    self_.borrow_mut().result = val;
                    self_.borrow().result_changed();
                });
            });
            std::thread::spawn(move || {
                // do stuff asynchronously ...
                let r = QString::from("Hello ".to_owned() + &name);
                set_value(r);
            }).join();
        })
    }
    # let obj = std::cell::RefCell::new(MyAsyncObject::default());
    # let mut engine = QmlEngine::new();
    # unsafe { qmetaobject::connect(
    #     QObject::cpp_construct(&obj),
    #     obj.borrow().result_changed.to_cpp_representation(&*obj.borrow()),
    #     || engine.quit()
    # ) };
    # obj.borrow().recompute_result("World".into());
    # engine.exec();
    # assert_eq!(obj.borrow().result, QString::from("Hello World"));
    ```
*/

#![recursion_limit = "10240"]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::needless_pass_by_value))] // Too many of that for qt types. (FIXME)
#![cfg_attr(feature = "cargo-clippy", allow(clippy::cognitive_complexity))]

#[macro_use]
extern crate cpp;

#[allow(unused_imports)]
#[macro_use]
extern crate qmetaobject_impl;
#[doc(hidden)]
pub use qmetaobject_impl::*;

// In order to be able to use the lazy_static macro from the QObject custom derive, we re-export
// it under a new name qmetaobject_lazy_static.
extern crate lazy_static;
#[allow(unused_imports)]
#[doc(hidden)]
pub use lazy_static::*;
#[doc(hidden)]
#[macro_export]
macro_rules! qmetaobject_lazy_static { ($($t:tt)*) => { lazy_static!($($t)*) } }

use std::cell::RefCell;
use std::os::raw::{c_char, c_void};

pub use qttypes;

pub use crate::log::*;
pub use connections::RustSignal;
pub use connections::{connect, Signal, SignalInner};
pub use future::*;
pub use itemmodel::*;
pub use listmodel::*;
pub use qmetatype::*;
pub use qtdeclarative::*;
#[cfg(qt_5_7)]
pub use qtquickcontrols2::*;
pub use qttypes::*;
pub use tablemodel::*;

pub mod connections;
pub mod future;
pub mod itemmodel;
pub mod listmodel;
pub mod log;
pub mod qmetatype;
pub mod qrc;
pub mod qtdeclarative;
#[cfg(qt_5_7)]
pub mod qtquickcontrols2;
pub mod scenegraph;
pub mod tablemodel;
#[cfg(feature = "webengine")]
pub mod webengine;

cpp! {{
    #include <qmetaobject_rust.hpp>
}}

#[doc(hidden)]
pub struct QObjectCppWrapper {
    ptr: *mut c_void,
}

impl Drop for QObjectCppWrapper {
    fn drop(&mut self) {
        let ptr = self.ptr;
        cpp!(unsafe [ptr as "QObject *"] {
            // The event 513 is caught by RustObject and deletes the object.
            QEvent e = QEvent(QEvent::Type(QtJambi_EventType_DeleteOnMainThread));
            if (ptr) {
                ptr->event(&e);
            }
        });
    }
}

impl Default for QObjectCppWrapper {
    fn default() -> QObjectCppWrapper {
        QObjectCppWrapper { ptr: std::ptr::null_mut() }
    }
}

impl QObjectCppWrapper {
    pub fn get(&self) -> *mut c_void {
        self.ptr
    }

    pub fn set(&mut self, val: *mut c_void) {
        self.ptr = val;
    }
}

#[doc(hidden)]
#[repr(C)]
pub struct QObjectDescription {
    pub size: usize,
    pub meta_object: *const QMetaObject,
    pub create: unsafe extern "C" fn(
        pinned_object: *const c_void,
        trait_object_ptr: *const c_void,
    ) -> *mut c_void,
    pub qml_construct: unsafe extern "C" fn(
        mem: *mut c_void,
        pinned_object: *const c_void,
        trait_object_ptr: *const c_void,
        extra_destruct: extern "C" fn(*mut c_void),
    ),
    pub get_rust_refcell: unsafe extern "C" fn(*mut c_void) -> *const RefCell<dyn QObject>,
}

/// Trait that is implemented by the QObject custom derive macro
///
/// Do not implement this trait yourself, use `#[derive(QObject)]`.
///
/// The method of this trait fits into two categories: the ones that are re-implemented by
/// the custom derive, and the ones that are used by this macro and need to be implemented
/// by other QObject-like trait which you use in the qt_base_class! macro.
pub trait QObject {
    // Functions re-implemented by the custom derive:

    /// Returns a pointer to a meta object
    fn meta_object(&self) -> *const QMetaObject;

    /// Returns a pointer to a meta object
    fn static_meta_object() -> *const QMetaObject
    where
        Self: Sized;

    /// return a C++ pointer to the QObject*  (can be null if not yet initialized)
    fn get_cpp_object(&self) -> *mut c_void;

    /// Construct the C++ Object.
    ///
    /// Note, once this function is called, the object must not be moved in memory.
    unsafe fn cpp_construct(pined: &RefCell<Self>) -> *mut c_void
    where
        Self: Sized;

    /// Construct the C++ Object, suitable for callbacks to construct QML objects.
    unsafe fn qml_construct(
        pined: &RefCell<Self>,
        mem: *mut c_void,
        extra_destruct: extern "C" fn(*mut c_void),
    ) where
        Self: Sized;

    /// Return the size of the C++ object
    fn cpp_size() -> usize
    where
        Self: Sized;

    /// Return a rust object belonging to a C++ object
    unsafe fn get_from_cpp<'a>(p: *mut c_void) -> QObjectPinned<'a, Self>
    where
        Self: Sized;

    // Part of the trait structure that sub trait must have.
    // Copy/paste this code replacing QObject with the type.

    /// Returns a QObjectDescription for this type
    fn get_object_description() -> &'static QObjectDescription
    where
        Self: Sized,
    {
        unsafe {
            &*cpp!([]-> *const QObjectDescription as "RustObjectDescription const *" {
                return rustObjectDescription<RustObject<QObject>>();
            })
        }
    }
}

impl dyn QObject {
    /// Creates a C++ object and construct a QVariant containing a pointer to it.
    ///
    /// The cpp_construct function must already have been called.
    ///
    /// FIXME: should probably not be used. Prefer using a QmlEngine::new_qobject.
    /// QVariant is unsafe as it does not manage life time
    pub unsafe fn as_qvariant(&self) -> QVariant {
        let self_ = self.get_cpp_object();
        cpp! {[self_ as "QObject*"] -> QVariant as "QVariant"  {
            return QVariant::fromValue(self_);
        }}
    }

    /// See Qt documentation for QObject::destroyed
    pub fn destroyed_signal() -> Signal<fn()> {
        unsafe {
            Signal::new(cpp!([] -> SignalInner as "SignalInner"  {
                return &QObject::destroyed;
            }))
        }
    }

    /// See Qt documentation for QObject::setObjectName
    // FIXME. take self by special reference?  panic if cpp_object does not exist?
    pub fn set_object_name(&self, name: QString) {
        let self_ = self.get_cpp_object();
        unsafe {
            cpp!([self_ as "QObject*", name as "QString"] {
                if (self_) self_->setObjectName(std::move(name));
            })
        }
    }

    /// See Qt documentation for QObject::objectNameChanged
    pub fn object_name_changed_signal() -> Signal<fn(QString)> {
        unsafe {
            Signal::new(cpp!([] -> SignalInner as "SignalInner"  {
                return &QObject::objectNameChanged;
            }))
        }
    }
}

cpp_class!(unsafe struct QPointerImpl as "QPointer<QObject>");

/// A Wrapper around a QPointer
// (we only need a *const T to support the !Sized case. (Maybe there is a better way)
pub struct QPointer<T: QObject + ?Sized>(QPointerImpl, *const T);
impl<T: QObject + ?Sized> QPointer<T> {
    /// Returns a pointer to the cpp object (null if it was deleted)
    pub fn cpp_ptr(&self) -> *mut c_void {
        let x = &self.0;
        cpp!(unsafe [x as "QPointer<QObject> *"] -> *mut c_void as "QObject *" {
            return x->data();
        })
    }

    /// Returns a reference to the `QObject`, or None if it was deleted
    pub fn as_ref(&self) -> Option<&T> {
        let x = self.cpp_ptr();
        if x.is_null() {
            None
        } else {
            unsafe { Some(&*self.1) }
        }
    }

    /// Returns true if the object was default constructed or constructed with an object which
    /// is now deleted
    pub fn is_null(&self) -> bool {
        self.cpp_ptr().is_null()
    }
}

impl<T: QObject> QPointer<T> {
    /// Returns a pinned reference to the QObject, or None if it was deleted
    pub fn as_pinned(&self) -> Option<QObjectPinned<T>> {
        let x = self.cpp_ptr();
        if x.is_null() {
            None
        } else {
            Some(unsafe { T::get_from_cpp(x) })
        }
    }
}

impl<'a, T: QObject + ?Sized> From<&'a T> for QPointer<T> {
    /// Creates a QPointer from a reference to a QObject.
    /// The corresponding C++ object must have already been created.
    fn from(obj: &'a T) -> Self {
        let cpp_obj = obj.get_cpp_object();
        QPointer(
            cpp!(unsafe [cpp_obj as "QObject *"] -> QPointerImpl  as "QPointer<QObject>" {
                return cpp_obj; // implicit constructor
            }),
            obj as *const T,
        )
    }
}

impl<T: QObject> Default for QPointer<T> {
    fn default() -> Self {
        QPointer(Default::default(), std::ptr::null())
    }
}

impl<T: QObject + ?Sized> Clone for QPointer<T> {
    fn clone(&self) -> Self {
        QPointer(self.0.clone(), self.1)
    }
}

/// Same as std::cell::RefMut, but does not allow to move from
pub struct QObjectRefMut<'b, T: QObject + ?Sized + 'b> {
    old_value: *mut c_void,
    inner: std::cell::RefMut<'b, T>,
}

impl<'b, T: QObject + ?Sized> std::ops::Deref for QObjectRefMut<'b, T> {
    type Target = std::cell::RefMut<'b, T>;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<'b, T: QObject + ?Sized> std::ops::DerefMut for QObjectRefMut<'b, T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl<'b, T: QObject + ?Sized + 'b> Drop for QObjectRefMut<'b, T> {
    #[inline]
    fn drop(&mut self) {
        assert_eq!(
            self.old_value,
            self.get_cpp_object(),
            "Internal pointer changed while borrowed"
        );
    }
}

/// A reference to a RefCell<T>, where T is a QObject, which does not move in memory
#[repr(transparent)]
pub struct QObjectPinned<'pin, T: QObject + ?Sized + 'pin>(&'pin RefCell<T>);

impl<'pin, T: QObject + ?Sized + 'pin> Clone for QObjectPinned<'pin, T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<'pin, T: QObject + ?Sized + 'pin> Copy for QObjectPinned<'pin, T> {}

impl<'pin, T: QObject + ?Sized + 'pin> QObjectPinned<'pin, T> {
    /// Borrow the object
    // FIXME: there are too many cases for which we want reentrance after borrowing
    //pub fn borrow(&self) -> std::cell::Ref<T> { self.0.borrow() }
    #[cfg_attr(feature = "cargo-clippy", allow(clippy::should_implement_trait))]
    pub fn borrow(&self) -> &T {
        unsafe { &*self.0.as_ptr() }
    }
    pub fn borrow_mut(&self) -> QObjectRefMut<T> {
        let x = self.0.borrow_mut();
        QObjectRefMut { old_value: x.get_cpp_object(), inner: x }
    }
    pub fn as_ptr(&self) -> *mut T {
        self.0.as_ptr()
    }
}

impl<'pin, T: QObject + ?Sized + 'pin> QObjectPinned<'pin, T> {
    /// Internal function used from the code generated by the QObject derive macro
    /// unsafe because one must ensure it does not move in memory
    pub unsafe fn new(inner: &'pin RefCell<T>) -> Self {
        QObjectPinned(inner)
    }
}

impl<'pin, T: QObject + 'pin> QObjectPinned<'pin, T> {
    /// Get the pointer ot the C++ Object, or crate it if it was not yet created
    pub fn get_or_create_cpp_object(self) -> *mut c_void {
        let r = unsafe { &*self.0.as_ptr() }.get_cpp_object();
        if r.is_null() {
            unsafe { QObject::cpp_construct(self.0) }
        } else {
            r
        }
    }
}

/// A wrapper around RefCell<T>, whose content cannot be move in memory
pub struct QObjectBox<T: QObject + ?Sized>(Box<RefCell<T>>);

impl<T: QObject> QObjectBox<T> {
    pub fn new(obj: T) -> Self {
        QObjectBox(Box::new(RefCell::new(obj)))
    }
}

impl<T: QObject + ?Sized> QObjectBox<T> {
    pub fn pinned(&self) -> QObjectPinned<T> {
        unsafe { QObjectPinned::new(&self.0) }
    }
}

/// Create the C++ object and return a C++ pointer to a QObject.
///
/// The ownership is given to CPP, the resulting QObject* ptr need to be used somewhere
/// that takes ownership
///
/// Panics if the C++ object was already created.
pub fn into_leaked_cpp_ptr<T: QObject>(obj: T) -> *mut c_void {
    let b = Box::new(RefCell::new(obj));
    let obj_ptr = unsafe { QObject::cpp_construct(&b) };
    std::boxed::Box::into_raw(b);
    obj_ptr
}

/// Trait that is implemented by the QGadget custom derive macro
///
/// Do not implement this trait yourself, use `#[derive(QGadget)]`.
pub trait QGadget {
    /// Returns a pointer to a meta object
    fn meta_object(&self) -> *const QMetaObject;

    /// Returns a pointer to a meta object
    fn static_meta_object() -> *const QMetaObject
    where
        Self: Sized;
}

/// Trait that is implemented by the QEnum custom derive macro
///
/// Do not implement this trait yourself, use `#[derive(QEnum)]`.
pub trait QEnum {
    /// Returns a pointer to a meta object
    fn static_meta_object() -> *const QMetaObject
    where
        Self: Sized;
}

#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn RustObject_metaObject(p: *mut RefCell<dyn QObject>) -> *const QMetaObject {
    (*(*p).as_ptr()).meta_object()
}

#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn RustObject_destruct(p: *mut RefCell<dyn QObject>) {
    // We are destroyed from the C++ code, which means that the object was owned by C++ and we
    // can destroy the rust object as well
    let _b = Box::from_raw(p);
}

/// This function is called from the implementation of the signal.
#[doc(hidden)]
pub unsafe fn invoke_signal(
    object: *mut c_void,
    meta: *const QMetaObject,
    id: u32,
    a: &[*mut c_void],
) {
    let a = a.as_ptr();
    cpp!([
        object as "QObject *",
        meta as "const QMetaObject *",
        id as "int",
        a as "void **"
    ] {
        if (!object) {
            return;
        }
        QMetaObject::activate(object, meta, id, a);
    })
}

/// Wrapper for `QMetaObject`'s private data's `StaticMetacallFunction` typedef.
type StaticMetacallFunction = Option<
    extern "C" fn(
        o: *mut c_void, // FIXME: should be QObject or something
        c: u32,
        idx: u32,
        a: *const *mut c_void,
    ),
>;

/// Same as a C++ QMetaObject.
#[doc(hidden)]
#[repr(C)]
pub struct QMetaObject {
    // fields are slightly renamed from Qt to match Rust code style
    pub super_data: *const QMetaObject,
    pub string_data: *const u8,
    pub data: *const u32,
    pub static_metacall: StaticMetacallFunction,
    pub meta_types: *const c_void,
    pub extra_data: *const c_void,
}

unsafe impl Sync for QMetaObject {}
unsafe impl Send for QMetaObject {}

/// This macro must be used once as a type in a struct that derives from QObject.
/// It is anotate from which QObject like trait it is supposed to derive.
/// the field which it annotate will be an internal property holding a pointer
/// to the actual C++ object
///
/// The trait needs to be like the QObject trait, see the documentation of the QObject trait.
///
/// ```
/// # #[macro_use] extern crate qmetaobject; use qmetaobject::QObject;
/// #[derive(QObject)]
/// struct Foo {
///    base : qt_base_class!(trait QObject),
/// }
/// ```
///
/// Note: in the future, the plan is to extent so you could derive from other struct by doing
/// `base : qt_base_class(struct Foo)`. But this is not yet implemented
#[macro_export]
macro_rules! qt_base_class {
    ($($t:tt)*) => {
        $crate::QObjectCppWrapper
    };
}

/// This macro can be used as a type of a field and can then turn this field in a Qt property.
/// The first parameter is the type of this property. Then we can have the meta keywords similar
/// to these found in Q_PROPERTY.
///
/// Can be used within a struct that derives from QObject or QGadget
///
/// `NOTIFY` followed by the name of a signal that need to be declared separately.
/// `WRITE` followed by the name of a setter. `READ` follow by the name of a getter. Note that
/// these are not mandatory and if no setter or no getter exist, it will set the field.
/// `CONST` is also supported.
///
/// `ALIAS` followed by an identifier allow to give a different name than the actual field name.
///
/// ```
/// # #[macro_use] extern crate qmetaobject; use qmetaobject::QObject;
/// #[derive(QObject)]
/// struct Foo {
///    base: qt_base_class!(trait QObject),
///    foo: qt_property!(u32; NOTIFY foo_changed WRITE set_foo),
///    foo_changed: qt_signal!(),
/// }
///
/// impl Foo {
///    fn set_foo(&mut self, val: u32) { self.foo = val; }
/// }
/// ```
#[macro_export]
macro_rules! qt_property {
    ($t:ty $(; $($rest:tt)*)*) => {
        $t
    };
}

/// This macro can be used to declare a method which will become a meta method.
///
/// Inside you can either declare the method signature, or write the full method.
///
/// Can be used within a struct that derives from QObject or QGadget
///
/// ```
/// # #[macro_use] extern crate qmetaobject; use qmetaobject::QObject;
/// #[derive(QObject)]
/// struct Foo {
///    base: qt_base_class!(trait QObject),
///    defined_method: qt_method!(fn defined_method(&self, foo: u32) -> u32 {
///       println!("contents goes here.");
///       return 42;
///    }),
///    out_of_line_method: qt_method!(fn(&self, foo: u32)-> u32),
/// }
///
/// impl Foo {
///    fn out_of_line_method(&mut self, foo: u32) -> u32 {
///       println!("Or here.");
///       return 69;
///    }
/// }
/// ```
#[macro_export]
macro_rules! qt_method {
    ($($t:tt)*) => { ::std::marker::PhantomData<()> };
}

/// Declares a signal
///
/// Inside you can either declare the method signature, or write the full method.
///
/// To be used within a struct that derives from QObject
///
/// ```
/// # #[macro_use] extern crate qmetaobject; use qmetaobject::QObject;
/// #[derive(QObject)]
/// struct Foo {
///    base: qt_base_class!(trait QObject),
///    my_signal: qt_signal!(xx: u32, yy: String),
/// }
///
/// fn some_code(foo: &mut Foo) {
///    foo.my_signal(42, "42".into()); // emits the signal
/// }
/// ```
#[macro_export]
macro_rules! qt_signal {
    ($( $name:ident : $ty:ty ),*) => { $crate::RustSignal<fn( $( $ty ),* )> };
}

/// Equivalent to the Q_PLUGIN_METADATA macro.
///
/// To be used within a struct that derives from QObject, and it should contain a string which is
/// the IID
///
/// ```
/// # #[macro_use] extern crate qmetaobject;
/// # use qmetaobject::qtdeclarative::QQmlExtensionPlugin;
/// #[derive(Default, QObject)]
/// struct MyPlugin {
///     base: qt_base_class!(trait QQmlExtensionPlugin),
///     plugin: qt_plugin!("org.qt-project.Qt.QQmlExtensionInterface/1.0")
/// }
/// # impl QQmlExtensionPlugin for MyPlugin {
/// #     fn register_types(&mut self, uri: &std::ffi::CStr) {}
/// # }
/// ```
#[macro_export]
macro_rules! qt_plugin {
    ($($t:tt)*) => { std::marker::PhantomData<()> };
}

cpp! {{
    struct FnBoxWrapper {
        /// Wrapped Box<dyn FnMut()>
        TraitObject fnbox;

        ~FnBoxWrapper() {
            if (fnbox.isValid()) {
                rust!(FnBoxWrapper_destructor [fnbox: *mut dyn FnMut() as "TraitObject"] {
                    unsafe { let _ = Box::from_raw(fnbox); }
                });
            }
        }

        /// Copying is not allowed.
        FnBoxWrapper &operator=(const FnBoxWrapper&) = delete;
#if false && QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
        FnBoxWrapper(const FnBoxWrapper&) = delete;
#else
        // Prior to Qt 5.10 we can't have move-only wrapper. Just do the auto_ptr kind of hack.
        FnBoxWrapper(const FnBoxWrapper &o) : fnbox(o.fnbox) {
            const_cast<FnBoxWrapper &>(o).fnbox = {};
        }
#endif

        /// Moving is allowed, since `Box<FnMut()>` itself is not pinned.
        FnBoxWrapper(FnBoxWrapper &&o) : fnbox(o.fnbox) {
            o.fnbox = {};
        }
        FnBoxWrapper &operator=(FnBoxWrapper &&o) {
            std::swap(o.fnbox, fnbox);
            return *this;
        }

        /// Call boxed function in rust.
        void operator()() {
            rust!(FnBoxWrapper_operator [fnbox : *mut dyn FnMut() as "TraitObject"] {
                unsafe { (*fnbox)(); }
            });
        }
    };

    template<typename T>
    static void invokeMethod(QObject *reciever, T &&func) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
        QMetaObject::invokeMethod(reciever, std::forward<T>(func), Qt::QueuedConnection); // does not allow move-only
#else
        // We can't use QTimer::singleShot because "Timers can only be used with threads started with QThread"
        QObject o;
        QObject::connect(&o, &QObject::destroyed, reciever, std::forward<T>(func), Qt::QueuedConnection);
#endif
    }
}}

/// Call the callback once, after a given duration.
pub fn single_shot<F>(interval: std::time::Duration, func: F)
where
    F: FnMut() + 'static,
{
    let func_box: Box<dyn FnMut()> = Box::new(func);
    let mut func_raw = Box::into_raw(func_box);

    let interval_ms: u32 = interval.as_secs() as u32 * 1000 + interval.subsec_nanos() * 1e-6 as u32;

    cpp!(unsafe [interval_ms as "int", mut func_raw as "FnBoxWrapper"] {
        QTimer::singleShot(interval_ms, std::move(func_raw));
    });
}

/// Create a callback to invoke a queued callback in the current thread.
///
/// Returns a callback that can be called in any thread. Calling the callback will then call the
/// given closure in the current Qt thread.
///
/// If the current thread does no longer have an event loop when the callback is sent, the
/// callback will not be recieved.
///
/// ```
/// # extern crate qmetaobject;
/// # use qmetaobject::queued_callback;
/// let callback = queued_callback(|()| println!("hello from main thread"));
/// std::thread::spawn(move || {callback(());}).join();
/// ```
pub fn queued_callback<T: Send, F: FnMut(T) + 'static>(
    func: F,
) -> impl Fn(T) + Send + Sync + Clone {
    let current_thread = cpp!(unsafe [] -> QPointerImpl as "QPointer<QThread>" {
        return QThread::currentThread();
    });

    // In this case, it is safe to send the function to another thread, as we will only call it
    // from this thread.
    // We put it in a RefCell so we can call it mutably.
    struct UnsafeSendFn<T>(RefCell<T>);
    unsafe impl<T> Send for UnsafeSendFn<T> {}
    unsafe impl<T> Sync for UnsafeSendFn<T> {}
    // put func in an arc because we need to keep it alive as long as the internal Box<FnMut> is
    // alive. (And we can't just move it there because the returned closure can be called several
    // times.
    let func = std::sync::Arc::new(UnsafeSendFn(RefCell::new(func)));

    move |x| {
        let mut x = Some(x); // Workaround the fact we can't have a Box<FnOnce>
        let func = func.clone();
        let func: Box<dyn FnMut()> = Box::new(move || {
            // the borrow_mut could panic if the function was called recursively. This could happen
            // if the event-loop re-enter.
            let f = &mut (*(func.0).borrow_mut());
            if let Some(x) = x.take() {
                f(x);
            };
        });
        // C++ destructor `~FnBoxWrapper` takes care of the memory.
        let mut func_raw = Box::into_raw(func);
        cpp!(unsafe [mut func_raw as "FnBoxWrapper", current_thread as "QPointer<QThread>"] {
            if (!current_thread) {
                return;
            }
            if (!qApp || current_thread != qApp->thread()) {
                QObject *reciever = new QObject();
                reciever->moveToThread(current_thread);
                invokeMethod(reciever, std::move(func_raw));
                reciever->deleteLater();
            } else {
                invokeMethod(qApp, std::move(func_raw));
            }
        });
    }
}

/* Small helper function for Rust_QAbstractItemModel::roleNames */
fn add_to_hash(hash: *mut c_void, key: i32, value: QByteArray) {
    cpp!(unsafe [
        hash as "QHash<int, QByteArray> *",
        key as "int",
        value as "QByteArray"
    ] {
        (*hash)[key] = std::move(value);
    });
}

/// Refer to the documentation of Qt::UserRole
pub const USER_ROLE: i32 = 0x0100;

/// Embed files and made them available to the Qt resource system.
///
/// The macro accepts an identifier with optional preceding visibility modifier,
/// and a comma-separated list of resources. Then macro generates a function
/// with given name and visibility, which can be used to register all the
/// resources.
///
/// # Input
///
/// The macro accepts the following formal grammar in pseudo [rust macro syntax][macro-doc]:
/// ```txt
/// macro call ::= qrc!( $f:Function $( $r:Recource ),* )
/// Function   ::= $v:vis $name:ident
/// Resource   ::= $( $base_dir:physical as )? $prefix:virtual { $( $f:File ),* }
/// File       ::= $path:physical $( as $alias:virtual )?
///
/// physical   ::= $path:literal
/// virtual    ::= $path:literal
/// ```
///
/// _Function_ is the name for the generated function, optionally preceded by
/// the visibility modifier (`pub(crate)` etc.)
///
/// _Physical_ path literal represents path on a local file system;
/// _virtual_ path represents virtual path in the generated qrc
/// resource tree accessible at `qrc:///virtual/path` URI.
///
/// **Note** that for _Resource_ physical part is optional,
/// meanwhile _File_ has optional _Virtual_ part.
///
/// _Resources_ and _Files_ are comma-separated lists.
///
/// _Resources_ consist of a
///  - `$base_dir:physical`: optional path to base directory on local file
///    system, separated from the prefix by the `as` keyword.
///    By default, base directory is the cargo project's root - directory with
///    Cargo.toml, a.k.a. [`$CARGO_MANIFEST_DIR`][].
///    (Custom extention which does not interfere with qrc format,
///    but merely resolves physical path of files in this resource relative
///    to the base directory, and helps keeping both project's root directory
///    and resource definitions clean and short.)
///  - `$prefix:virtual`: prefix directory path in qrc's virtual file system.
///    It will be prepended to every file's virtual path.
///    (Corresponds to qrc format.)
///  - A curly-braced list of comma-separated _Files_.
///
/// _Files_ are specified as
///  - `$path:physical`: path to the file on local file system.
///    Relative to the resource's base directory.
///    (Corresponds to qrc format, with the exception below.)
///  - `$alias:virtual`: an optional alias in qrc's virtual file system,
///    separated from the physical path by the `as` keyword.
///    By default, virtual path of a file is the same as its phisycal path.
///    (Corresponds to qrc format).
///  - **Note** about physical path: _resource_'s base directory is prepended to
///    the file's physical path before looking for the file on the local file
///    system, but after the physical path is cloned to the virtual counterpart
///    (if the later one was omitted, i.e. no explicit alias was given).
///
/// It does not matter if the prefix has leading '/' or not.
///
/// # Output
///
/// The macro creates a function with given name and visibility modifier,
/// that needs to be run in order to register the resource. Function is
/// idempotent, i.e. calling it more than once is allowed but has no effect.
///
/// # Example
///
/// Consider this project files structure:
/// ```text
/// .
/// ├── Cargo.toml
/// ├── tests/qml
/// │   ├── qml.qrc
/// │   ├── main.qml
/// │   └── Bar.qml
/// └── src
///     └── main.rs
/// ```
/// then the following Rust code:
/// ```
/// # extern crate qmetaobject;
/// # use qmetaobject::qrc;
/// # // For maintainers: this is actually tested against real files.
/// // private fn, and base directory shortcut
/// qrc!(my_resource_1,
///     "tests/qml" as "foo1" {
///         "main.qml",
///         "Bar.qml" as "baz/Foo.qml",
///      }
/// );
///
/// # // this is a test of visibility modifier
/// # mod private {
/// # use super::*;
/// // public fn, no shortcuts
/// qrc!(pub my_resource_2,
///     "foo2" {
///         // either use file alias or re-organize files
///         "tests/qml/main.qml" as "main.qml",
///         "tests/qml/Bar.qml" as "baz/Foo.qml",
///      }
/// );
/// # }
///
/// # fn use_resource(_r: &str) {
/// #     // at the time of writing, it is the only way to test the existence of a resource.
/// #     use qmetaobject::*;
/// #     let mut engine = QmlEngine::new();
/// #     let mut c = QmlComponent::new(&engine);
/// #     c.load_url(QUrl::from(QString::from("qrc:/foo2/baz/Foo.qml")), CompilationMode::PreferSynchronous);
/// #     assert_eq!(ComponentStatus::Ready, c.status());
/// #     engine.quit();
/// # }
/// # fn main() {
/// // registers the resource to Qt
/// my_resource_1();
/// # private::
/// my_resource_2();
/// // do something with resources
/// use_resource("qrc:/foo1/baz/Foo.qml");
/// use_resource("qrc:/foo2/baz/Foo.qml");
/// # }
/// ```
/// corresponds to the .qrc (`tests/qml/qml.qrc`) file:
/// ```xml
/// <RCC>
///     <qresource prefix="/foo">
///         <file>main.qml</file>
///         <file alias="baz/Foo.qml">Bar.qml</file>
///     </qresource>
/// </RCC>
/// ```
///
/// [macro-doc]: https://doc.rust-lang.org/reference/macros-by-example.html#metavariables
/// [`$CARGO_MANIFEST_DIR`]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
pub use qmetaobject_impl::qrc_internal as qrc;
// XXX: The line above re-exports the macro with proper documentation and doctests.