QPPromise::QPPromise(QObject* parent)
    : QObject(parent) {

    if (engine == nullptr) {
        engine = qmlEngine(parent);
        if (engine == nullptr)
            qFatal("Could not infer QML engine. Please call setEngine()");
        qWarning() << "Inferring QML engine pointer -- to squelch this warning, call QPPromise::setEngine() prior to "
                   "creating any QPPromise objects.";
    }

    QQmlComponent promiserComponent(engine);
    promiserComponent.setData("import QuickPromise 1.0\nPromise {}", QUrl());
    internalPromise = promiserComponent.create();
    internalPromise->setParent(this);

    connect(internalPromise, SIGNAL(fulfilled(QVariant)), this, SIGNAL(fulfilled(QVariant)));
    connect(internalPromise, SIGNAL(rejected(QVariant)), this, SIGNAL(rejected(QVariant)));
    connect(internalPromise, SIGNAL(settled(QVariant)), this, SIGNAL(settled(QVariant)));
}
QmlPromise::QmlPromise(QObject* parent)
    : QObject(parent) {
    auto engine = qmlEngine(parent);
    if (engine == nullptr)
        qFatal("Could not find QML engine. Unable to continue.");

    QQmlComponent promiserComponent(qmlEngine(parent));
    promiserComponent.setData("import QuickPromise 1.0\nPromise {}", QUrl());
    internalPromise = promiserComponent.create();

    QQmlEngine::setObjectOwnership(internalPromise, QQmlEngine::JavaScriptOwnership);
    connect(internalPromise, &QObject::destroyed, this, [this] {
        // Probably won't happen often, if ever, but if it does it could provide useful insights vis a vis debugging
        qDebug() << "Promise{} was garbage collected while QmlPromise still valid";
        internalPromise = nullptr;
    });
    connect(internalPromise, SIGNAL(fulfilled(QVariant)), this, SIGNAL(fulfilled(QVariant)));
    connect(internalPromise, SIGNAL(rejected(QVariant)), this, SIGNAL(rejected(QVariant)));
    connect(internalPromise, SIGNAL(settled(QVariant)), this, SIGNAL(settled()));
    connect(this, &QmlPromise::fulfilled, [this] { wasFulfilled = true; });
    connect(this, &QmlPromise::rejected, [this] { wasRejected = true; });
}