skyline/app/src/main/cpp/skyline/services/nvdrv/devices/deserialisation/deserialisation.h

84 lines
4.2 KiB
C++

// SPDX-License-Identifier: MIT OR MPL-2.0
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <type_traits>
#include <common.h>
#include "types.h"
namespace skyline::service::nvdrv::deserialisation {
template<typename Desc, typename ArgType> requires (Desc::In && IsIn<ArgType>::value)
constexpr ArgType DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset, std::array<size_t, NumSaveSlots> &saveSlots) {
auto out{buffer.subspan(offset).template as<ArgType, true>()};
offset += sizeof(ArgType);
return out;
}
template<typename Desc, typename ArgType> requires (Desc::Out && Desc::In && IsInOut<ArgType>::value)
constexpr ArgType DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset, std::array<size_t, NumSaveSlots> &saveSlots) {
auto &out{buffer.subspan(offset).template as<RemoveInOut<ArgType>, true>()};
offset += sizeof(RemoveInOut<ArgType>);
return out;
}
template<typename Desc, typename ArgType> requires (Desc::Out && IsOut<ArgType>::value)
constexpr ArgType DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset, std::array<size_t, NumSaveSlots> &saveSlots) {
auto out{Out(buffer.subspan(offset).template as<RemoveOut<ArgType>, true>())};
offset += sizeof(RemoveOut<ArgType>);
return out;
}
template<typename Desc, typename ArgType> requires (IsSlotSizeSpan<ArgType>::value)
constexpr auto DecodeArgument(span<u8, Desc::Size> buffer, size_t &offset, std::array<size_t, NumSaveSlots> &saveSlots) {
size_t bytes{saveSlots[ArgType::SaveSlot] * sizeof(RemoveSlotSizeSpan<ArgType>)};
auto out{buffer.subspan(offset, bytes).template cast<RemoveSlotSizeSpan<ArgType>, 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 <typename...Ts>
constexpr auto make_ref_tuple(Ts&&...ts) {
return std::tuple<Ts...>{std::forward<Ts>(ts)...};
}
template<typename Desc, typename ArgType, typename... ArgTypes>
constexpr auto DecodeArgumentsImpl(span<u8, Desc::Size> buffer, size_t &offset, std::array<size_t, NumSaveSlots> &saveSlots) {
if constexpr (IsAutoSizeSpan<ArgType>::value) {
// AutoSizeSpan needs to be the last argument
static_assert(sizeof...(ArgTypes) == 0);
return make_ref_tuple(buffer.subspan(offset).template cast<RemoveAutoSizeSpan<ArgType>, std::dynamic_extent, true>());
} else if constexpr (IsPad<ArgType>::value) {
offset += ArgType::Bytes;
return DecodeArgumentsImpl<Desc, ArgTypes...>(buffer, offset, saveSlots);
} else if constexpr (IsSave<ArgType>::value) {
saveSlots[ArgType::SaveSlot] = buffer.subspan(offset).template as<RemoveSave<ArgType>, true>();
offset += sizeof(RemoveSave<ArgType>);
return DecodeArgumentsImpl<Desc, ArgTypes...>(buffer, offset, saveSlots);
} else {
if constexpr(sizeof...(ArgTypes) == 0) {
return make_ref_tuple(DecodeArgument<Desc, ArgType>(buffer, offset, saveSlots));
} else {
return std::tuple_cat(make_ref_tuple(DecodeArgument<Desc, ArgType>(buffer, offset, saveSlots)),
DecodeArgumentsImpl<Desc, ArgTypes...>(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<typename Desc, typename... ArgTypes>
constexpr auto DecodeArguments(span<u8, Desc::Size> buffer) {
size_t offset{};
std::array<size_t, NumSaveSlots> saveSlots{}; // No need to zero init as used slots will always be loaded first
return DecodeArgumentsImpl<Desc, ArgTypes...>(buffer, offset, saveSlots);
}
}