/* * Copyright (C) 2019 Aetf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 or (at your option) * version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KEEPASSXC_FDOSECRETS_DBUSRETURN_H #define KEEPASSXC_FDOSECRETS_DBUSRETURN_H #include #include #include #include namespace FdoSecrets { namespace details { class DBusReturnImpl { public: /** * Check if this object contains an error * @return true if it contains an error, false otherwise. */ bool isError() const { return !m_errorName.isEmpty(); } /** * Get the error name * @return */ QString errorName() const { return m_errorName; } void okOrDie() const { Q_ASSERT(!isError()); } protected: struct WithErrorTag { }; /** * Construct from an error * @param errorName * @param value */ DBusReturnImpl(QString errorName, WithErrorTag) : m_errorName(std::move(errorName)) { } DBusReturnImpl() = default; protected: QString m_errorName; }; } // namespace details /** * Either a return value or a DBus error * @tparam T */ template class DBusReturn : public details::DBusReturnImpl { protected: using DBusReturnImpl::DBusReturnImpl; public: using value_type = T; DBusReturn() = default; /** * Implicitly construct from a value * @param value */ DBusReturn(T&& value) // NOLINT(google-explicit-constructor) : m_value(std::move(value)) { } DBusReturn(const T& value) // NOLINT(google-explicit-constructor) : m_value(std::move(value)) { } /** * Implicitly convert from another error of different value type. * * @tparam U must not be the same as T * @param other */ template ::value>::type> DBusReturn(const DBusReturn& other) // NOLINT(google-explicit-constructor) : DBusReturn(other.errorName(), DBusReturnImpl::WithErrorTag{}) { Q_ASSERT(other.isError()); } /** * Construct from error * @param errorType * @return a DBusReturn object containing the error */ static DBusReturn Error(QDBusError::ErrorType errorType) { return DBusReturn{QDBusError::errorString(errorType), DBusReturnImpl::WithErrorTag{}}; } /** * Overloaded version * @param errorName * @return a DBusReturnImpl object containing the error */ static DBusReturn Error(QString errorName) { return DBusReturn{std::move(errorName), DBusReturnImpl::WithErrorTag{}}; } /** * Get a reference to the enclosed value * @return */ const T& value() const& { okOrDie(); return m_value; } /** * Get a rvalue reference to the enclosed value if this object is rvalue * @return a rvalue reference to the enclosed value */ T value() && { okOrDie(); return std::move(m_value); } /** * Get value or handle the error by the passed in dbus object * @tparam P * @param p * @return */ template T valueOrHandle(P* p) const& { if (isError()) { if (p->calledFromDBus()) { p->sendErrorReply(errorName()); } return {}; } return m_value; } /** * Get value or handle the error by the passed in dbus object * @tparam P * @param p * @return */ template T&& valueOrHandle(P* p) && { if (isError()) { if (p->calledFromDBus()) { p->sendErrorReply(errorName()); } } return std::move(m_value); } private: T m_value{}; }; template <> class DBusReturn : public details::DBusReturnImpl { protected: using DBusReturnImpl::DBusReturnImpl; public: using value_type = void; DBusReturn() = default; /** * Implicitly convert from another error of different value type. * * @tparam U must not be the same as T * @param other */ template ::value>::type> DBusReturn(const DBusReturn& other) // NOLINT(google-explicit-constructor) : DBusReturn(other.errorName(), DBusReturnImpl::WithErrorTag{}) { Q_ASSERT(other.isError()); } /** * Construct from error * @param errorType * @return a DBusReturn object containing the error */ static DBusReturn Error(QDBusError::ErrorType errorType) { return DBusReturn{QDBusError::errorString(errorType), DBusReturnImpl::WithErrorTag{}}; } /** * Overloaded version * @param errorName * @return a DBusReturnImpl object containing the error */ static DBusReturn Error(QString errorName) { return DBusReturn{std::move(errorName), DBusReturnImpl::WithErrorTag{}}; } /** * If this is return contains an error, handle it if we were called from DBus * @tparam P * @param p */ template void handle(P* p) const { if (isError()) { if (p->calledFromDBus()) { p->sendErrorReply(errorName()); } } } }; } // namespace FdoSecrets #endif // KEEPASSXC_FDOSECRETS_DBUSRETURN_H