// SPDX-License-Identifier: MIT OR MPL-2.0 // Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) #pragma once #include #include #include "types.h" namespace skyline::service::nvdrv::deserialisation { template requires (Desc::In && IsIn::value) constexpr ArgType DecodeArgument(span buffer, size_t &offset, std::array &saveSlots) { auto out{buffer.subspan(offset).template as()}; offset += sizeof(ArgType); return out; } template requires (Desc::Out && Desc::In && IsInOut::value) constexpr ArgType DecodeArgument(span buffer, size_t &offset, std::array &saveSlots) { auto &out{buffer.subspan(offset).template as, true>()}; offset += sizeof(RemoveInOut); return out; } template requires (Desc::Out && IsOut::value) constexpr ArgType DecodeArgument(span buffer, size_t &offset, std::array &saveSlots) { auto out{Out(buffer.subspan(offset).template as, true>())}; offset += sizeof(RemoveOut); return out; } template requires (IsSlotSizeSpan::value) constexpr auto DecodeArgument(span buffer, size_t &offset, std::array &saveSlots) { size_t bytes{saveSlots[ArgType::SaveSlot] * sizeof(RemoveSlotSizeSpan)}; auto out{buffer.subspan(offset, bytes).template cast, std::dynamic_extent, true>()}; offset += bytes; // Return a simple `span` as that will be the function argument type as opposed to `SlotSizeSpan` return out; } /** * @brief Creates a reference preserving tuple of the given types */ template constexpr auto make_ref_tuple(Ts&&...ts) { return std::tuple{std::forward(ts)...}; } template constexpr auto DecodeArgumentsImpl(span buffer, size_t &offset, std::array &saveSlots) { if constexpr (IsAutoSizeSpan::value) { // AutoSizeSpan needs to be the last argument static_assert(sizeof...(ArgTypes) == 0); return make_ref_tuple(buffer.subspan(offset).template cast, std::dynamic_extent, true>()); } else if constexpr (IsPad::value) { offset += ArgType::Bytes; if constexpr(sizeof...(ArgTypes) == 0) { return std::tuple{}; } else { return DecodeArgumentsImpl(buffer, offset, saveSlots); } } else if constexpr (IsSave::value) { saveSlots[ArgType::SaveSlot] = buffer.subspan(offset).template as, true>(); offset += sizeof(RemoveSave); return DecodeArgumentsImpl(buffer, offset, saveSlots); } else { if constexpr(sizeof...(ArgTypes) == 0) { return make_ref_tuple(DecodeArgument(buffer, offset, saveSlots)); } else { return std::tuple_cat(make_ref_tuple(DecodeArgument(buffer, offset, saveSlots)), DecodeArgumentsImpl(buffer, offset, saveSlots)); } } } /** * @brief This fancy thing takes a varadic template of argument types and uses it to deserialise the given buffer * @tparam Desc A MetaIoctlDescriptor or MetaVariableIoctlDescriptor corresponding to the IOCTL that takes these arguments * @return A tuple containing the arguments to be passed to the IOCTL's handler */ template constexpr auto DecodeArguments(span buffer) { size_t offset{}; std::array saveSlots{}; // No need to zero init as used slots will always be loaded first return DecodeArgumentsImpl(buffer, offset, saveSlots); } }