/* * Copyright (c) 2018-2019 Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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 . */ #pragma once #include #include #include #include "ipc_out.hpp" #include "../firmware_version.hpp" class IpcResponseContext; struct ServiceCommandMeta { FirmwareVersion fw_low = FirmwareVersion_Max; FirmwareVersion fw_high = FirmwareVersion_Max; u32 cmd_id = 0; Result (*handler)(IpcResponseContext *) = nullptr; }; class IServiceObject { public: virtual ~IServiceObject() { } virtual bool IsMitmObject() const { return false; } }; #define SERVICE_DISPATCH_TABLE_NAME s_DispatchTable #define DEFINE_SERVICE_DISPATCH_TABLE static constexpr ServiceCommandMeta SERVICE_DISPATCH_TABLE_NAME[] template static constexpr size_t DispatchTableEntryCount() { static_assert(std::is_base_of::value, "DispatchTable owners must derive from IServiceObject"); return sizeof(T::SERVICE_DISPATCH_TABLE_NAME)/sizeof(ServiceCommandMeta); } template static constexpr const ServiceCommandMeta* DispatchTable() { static_assert(std::is_base_of::value, "DispatchTable owners must derive from IServiceObject"); return reinterpret_cast(&T::SERVICE_DISPATCH_TABLE_NAME); } template static constexpr uintptr_t ServiceObjectId() { static_assert(std::is_base_of::value, "Service Objects must derive from IServiceObject"); return reinterpret_cast(&T::SERVICE_DISPATCH_TABLE_NAME); } class ServiceObjectHolder { private: std::shared_ptr srv; const ServiceCommandMeta *dispatch_table; size_t entry_count; /* Private copy constructor. */ ServiceObjectHolder(const ServiceObjectHolder& other) : srv(other.srv), dispatch_table(other.dispatch_table), entry_count(other.entry_count) { } ServiceObjectHolder& operator=(const ServiceObjectHolder& other); public: /* Templated constructor ensures correct type id at runtime. */ template explicit ServiceObjectHolder(std::shared_ptr&& s) : srv(std::move(s)), dispatch_table(DispatchTable()), entry_count(DispatchTableEntryCount()) { } template ServiceImpl *GetServiceObject() const { if (GetServiceId() == ServiceObjectId()) { return static_cast(this->srv.get()); } return nullptr; } template ServiceImpl *GetServiceObjectUnsafe() const { return static_cast(this->srv.get()); } const ServiceCommandMeta *GetDispatchTable() const { return this->dispatch_table; } size_t GetDispatchTableEntryCount() const { return this->entry_count; } constexpr uintptr_t GetServiceId() const { return reinterpret_cast(this->dispatch_table); } bool IsMitmObject() const { return this->srv->IsMitmObject(); } /* Default constructor, move constructor, move assignment operator. */ ServiceObjectHolder() : srv(nullptr), dispatch_table(nullptr) { } ServiceObjectHolder(ServiceObjectHolder&& other) : srv(std::move(other.srv)), dispatch_table(std::move(other.dispatch_table)), entry_count(std::move(other.entry_count)) { } ServiceObjectHolder& operator=(ServiceObjectHolder&& other) { this->srv = other.srv; this->dispatch_table = other.dispatch_table; this->entry_count = other.entry_count; other.Reset(); return *this; } explicit operator bool() const { return this->srv != nullptr; } bool operator!() const { return this->srv == nullptr; } void Reset() { this->srv.reset(); this->dispatch_table = nullptr; this->entry_count = 0; } ServiceObjectHolder Clone() const { ServiceObjectHolder clone(*this); return clone; } };