/*
* Copyright (c) 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
#include
namespace ams::tipc {
struct ClientProcessId {
os::ProcessId value;
};
static_assert(std::is_trivial::value && sizeof(ClientProcessId) == sizeof(os::ProcessId), "ClientProcessId");
}
#if defined(ATMOSPHERE_OS_HORIZON)
namespace ams::tipc::impl {
/* Machinery for filtering type lists. */
template
struct TupleCat;
template
struct TupleCat, std::tuple> {
using type = std::tuple;
};
template typename Cond>
struct TupleFilter {
private:
template
struct ImplType;
template
struct ImplType> {
using type = Res;
};
template
struct ImplType> {
using type = typename std::conditional::value,
typename ImplType>::type, std::tuple>::type,
typename ImplType>::type
>::type;
};
public:
template
using FilteredType = typename ImplType, T>::type;
};
enum class ArgumentType {
InData,
OutData,
Buffer,
InHandle,
OutHandle,
ProcessId,
};
template
constexpr inline ArgumentType GetArgumentType = [] {
if constexpr (tipc::IsBuffer) {
return ArgumentType::Buffer;
} else if constexpr (std::same_as || std::same_as) {
return ArgumentType::InHandle;
} else if constexpr (std::same_as || std::same_as) {
return ArgumentType::OutHandle;
} else if constexpr (std::is_base_of::value) {
return ArgumentType::OutData;
} else if constexpr (std::same_as) {
return ArgumentType::ProcessId;
} else if constexpr (std::is_trivial::value && !std::is_pointer::value) {
return ArgumentType::InData;
} else if constexpr (std::is_same::value) {
return ArgumentType::InData;
} else {
static_assert(!std::is_same::value, "Invalid ArgumentType");
}
}();
template
struct ArgumentTypeFilter : public std::bool_constant == ArgT>{};
template
struct TypeEqualityFilter : public std::bool_constant::value>{};
/* Argument type filters. */
template
using InDataFilter = ArgumentTypeFilter;
template
using OutDataFilter = ArgumentTypeFilter;
template
using BufferFilter = ArgumentTypeFilter;
template
using InHandleFilter = ArgumentTypeFilter;
template
using OutHandleFilter = ArgumentTypeFilter;
template
using ProcessIdFilter = ArgumentTypeFilter;
/* Handle kind filters. */
template
using InMoveHandleFilter = TypeEqualityFilter;
template
using InCopyHandleFilter = TypeEqualityFilter;
template
using OutMoveHandleFilter = TypeEqualityFilter;
template
using OutCopyHandleFilter = TypeEqualityFilter;
template
struct BufferAttributeArrayGetter;
template
struct BufferAttributeArrayGetter> {
static constexpr std::array value = { BufferAttributes..., };
};
template<>
struct BufferAttributeArrayGetter> {
static constexpr std::array value{};
};
template
struct BufferAttributeCounter {
template
static constexpr size_t GetCount(const std::array &attributes_array) {
size_t count = 0;
for (size_t i = 0; i < Size; i++) {
if (Predicate(attributes_array[i])) {
count++;
}
}
return count;
}
};
static constexpr size_t InBufferPredicate(const u32 attribute) {
return (attribute & SfBufferAttr_In) && !(attribute & SfBufferAttr_Out);
}
static constexpr size_t OutBufferPredicate(const u32 attribute) {
return !(attribute & SfBufferAttr_In) && (attribute & SfBufferAttr_Out);
}
template
struct RawDataOffsetCalculator;
template
struct RawDataOffsetCalculator> {
private:
template
struct LayoutHelper {
static_assert(GetArgumentType == ArgumentType::InData, "LayoutHelper InData");
static constexpr size_t Alignment = alignof(T);
static constexpr size_t Size = sizeof(T);
};
template
struct LayoutHelper> {
static_assert(GetArgumentType == ArgumentType::InData, "LayoutHelper OutData");
static constexpr size_t Alignment = alignof(T);
static constexpr size_t Size = sizeof(T);
};
public:
static constexpr std::array Offsets = [] {
std::array offsets{};
offsets[0] = 0;
if constexpr (sizeof...(Ts) > 0) {
/* Get size, alignment for each type. */
const std::array sizes = { LayoutHelper::Size... };
const std::array aligns = { LayoutHelper::Alignment... };
/* We want to sort...by alignment. */
std::array map = {};
for (size_t i = 0; i < sizeof...(Ts); i++) { map[i] = i; }
/* TODO: Is sorting done on parameters? */
/* Sort?(map, aligns); */
/* Iterate over sorted sizes. */
size_t cur_offset = 0;
for (size_t i : map) {
cur_offset = util::AlignUp(cur_offset, aligns[i]);
offsets[i] = cur_offset;
cur_offset += sizes[i];
}
offsets[sizeof...(Ts)] = cur_offset;
}
return offsets;
}();
};
struct ArgumentSerializationInfo {
/* Type used to select from below fields. */
ArgumentType arg_type;
/* Raw data indexing. */
size_t in_raw_data_index;
size_t out_raw_data_index;
/* Buffer indexing. */
size_t buffer_index;
bool is_send_buffer;
size_t send_map_alias_index;
size_t recv_map_alias_index;
/* Handle indexing. */
size_t in_move_handle_index;
size_t in_copy_handle_index;
size_t out_move_handle_index;
size_t out_copy_handle_index;
};
template
struct CommandMetaInfo;
template
struct CommandMetaInfo<_CommandId, std::tuple> {
public:
static constexpr u16 CommandId = _CommandId;
using ArgsType = std::tuple::type...>;
using InDatas = TupleFilter::FilteredType;
using OutDatas = TupleFilter::FilteredType;
using Buffers = TupleFilter::FilteredType;
using InHandles = TupleFilter::FilteredType;
using OutHandles = TupleFilter::FilteredType;
using ProcessIds = TupleFilter::FilteredType;
static constexpr size_t NumInDatas = std::tuple_size::value;
static constexpr size_t NumOutDatas = std::tuple_size::value;
static constexpr size_t NumBuffers = std::tuple_size::value;
static constexpr size_t NumInHandles = std::tuple_size::value;
static constexpr size_t NumOutHandles = std::tuple_size::value;
static constexpr size_t NumProcessIds = std::tuple_size::value;
static constexpr bool HasProcessId = NumProcessIds >= 1;
static_assert(NumBuffers <= 8, "Methods must take in <= 8 Buffers");
static_assert(NumInHandles <= 8, "Methods must take in <= 8 Handles");
static_assert(NumOutHandles <= 8, "Methods must output <= 8 Handles");
static_assert(NumInHandles == 0, "In Handles not yet implemented!");
/* Buffer marshalling. */
static constexpr std::array BufferAttributes = BufferAttributeArrayGetter::value;
static constexpr size_t NumInBuffers = BufferAttributeCounter::GetCount(BufferAttributes);
static constexpr size_t NumOutBuffers = BufferAttributeCounter::GetCount(BufferAttributes);
/* In/Out data marshalling. */
static constexpr std::array InDataOffsets = RawDataOffsetCalculator::Offsets;
static constexpr size_t InDataSize = util::AlignUp(InDataOffsets[NumInDatas], alignof(u32));
static constexpr std::array OutDataOffsets = RawDataOffsetCalculator::Offsets;
static constexpr size_t OutDataSize = util::AlignUp(OutDataOffsets[NumOutDatas], alignof(u32));
/* Useful because reasons. */
static constexpr size_t OutDataAlign = []() -> size_t {
if constexpr (std::tuple_size::value) {
return alignof(typename std::tuple_element<0, OutDatas>::type);
}
return 0;
}();
/* Handle marshalling. */
static constexpr size_t NumInMoveHandles = std::tuple_size::FilteredType>::value;
static constexpr size_t NumInCopyHandles = std::tuple_size::FilteredType>::value;
static constexpr size_t NumOutMoveHandles = std::tuple_size::FilteredType>::value;
static constexpr size_t NumOutCopyHandles = std::tuple_size::FilteredType>::value;
static_assert(NumInMoveHandles + NumInCopyHandles == NumInHandles, "NumInMoveHandles + NumInCopyHandles == NumInHandles");
static_assert(NumOutMoveHandles + NumOutCopyHandles == NumOutHandles, "NumOutMoveHandles + NumOutCopyHandles == NumOutHandles");
/* tipc-specific accessors. */
static constexpr bool HasInSpecialHeader = HasProcessId || NumInHandles > 0;
static constexpr MessageBuffer::MessageHeader InMessageHeader{CommandId, HasInSpecialHeader, 0, NumInBuffers, NumOutBuffers, 0, InDataSize / sizeof(u32), 0};
static constexpr MessageBuffer::SpecialHeader InSpecialHeader{HasProcessId, NumInCopyHandles, NumInMoveHandles, HasInSpecialHeader};
static constexpr auto InMessageProcessIdIndex = MessageBuffer::GetSpecialDataIndex(InMessageHeader, InSpecialHeader);
static constexpr auto InMessageHandleIndex = MessageBuffer::GetSpecialDataIndex(InMessageHeader, InSpecialHeader) + (HasProcessId ? sizeof(u64) / sizeof(u32) : 0);
static constexpr auto InMessageBufferIndex = MessageBuffer::GetMapAliasDescriptorIndex(InMessageHeader, InSpecialHeader);
static constexpr auto InMessageRawDataIndex = MessageBuffer::GetRawDataIndex(InMessageHeader, InSpecialHeader);
static constexpr bool HasOutSpecialHeader = NumOutHandles > 0;
static constexpr MessageBuffer::MessageHeader OutMessageHeader{CommandId, HasOutSpecialHeader, 0, 0, 0, 0, (OutDataSize / sizeof(u32)) + 1, 0};
static constexpr MessageBuffer::SpecialHeader OutSpecialHeader{false, NumOutCopyHandles, NumOutMoveHandles, HasOutSpecialHeader};
static constexpr auto OutMessageHandleIndex = MessageBuffer::GetSpecialDataIndex(OutMessageHeader, OutSpecialHeader);
static constexpr auto OutMessageResultIndex = MessageBuffer::GetRawDataIndex(OutMessageHeader, OutSpecialHeader);
static constexpr auto OutMessageRawDataIndex = OutMessageResultIndex + 1;
static constexpr size_t InMessageTotalSize = (InMessageRawDataIndex * sizeof(u32)) + InDataSize;
static constexpr size_t OutMessageTotalSize = (OutMessageRawDataIndex * sizeof(u32)) + OutDataSize;
/* Construction of argument serialization structs. */
private:
template
struct ArgumentSerializationInfoConstructor;
template
struct ArgumentSerializationInfoConstructor> {
template
static constexpr ArgumentSerializationInfo ProcessUpdate(ArgumentSerializationInfo ¤t_info) {
/* Save a copy of the current state to return. */
ArgumentSerializationInfo returned_info = current_info;
constexpr auto arg_type = GetArgumentType;
returned_info.arg_type = arg_type;
if constexpr (arg_type == ArgumentType::InData) {
/* New rawdata, so increment index. */
current_info.in_raw_data_index++;
} else if constexpr (arg_type == ArgumentType::OutData) {
/* New rawdata, so increment index. */
current_info.out_raw_data_index++;
} else if constexpr (arg_type == ArgumentType::InHandle) {
/* New InHandle, increment the appropriate index. */
if constexpr (std::same_as) {
current_info.in_move_handle_index++;
} else if constexpr (std::same_as) {
current_info.in_copy_handle_index++;
} else {
static_assert(!std::is_same::value, "Invalid InHandle kind");
}
} else if constexpr (arg_type == ArgumentType::OutHandle) {
/* New OutHandle, increment the appropriate index. */
if constexpr (std::same_as) {
current_info.out_move_handle_index++;
} else if constexpr (std::same_as) {
current_info.out_copy_handle_index++;
} else {
static_assert(!std::is_same::value, "Invalid OutHandle kind");
}
} else if constexpr (arg_type == ArgumentType::Buffer) {
/* New Buffer, increment the appropriate index. */
const auto attributes = BufferAttributes[current_info.buffer_index++];
if (attributes & SfBufferAttr_In) {
returned_info.is_send_buffer = true;
current_info.send_map_alias_index++;
} else if (attributes & SfBufferAttr_Out) {
returned_info.is_send_buffer = false;
current_info.recv_map_alias_index++;
}
} else if constexpr (arg_type == ArgumentType::ProcessId) {
/* Nothing needs to be done to track process ids. */
} else {
static_assert(!std::is_same::value, "Invalid ArgumentType");
}
return returned_info;
}
static constexpr std::array ArgumentSerializationInfos = [] {
ArgumentSerializationInfo current_info = {};
return std::array{ ProcessUpdate(current_info)... };
}();
};
public:
static constexpr std::array::value> ArgumentSerializationInfos = ArgumentSerializationInfoConstructor::ArgumentSerializationInfos;
};
template
class OutRawHolder {
public:
static constexpr size_t Size = _Size;
static constexpr size_t Align = _Align ? _Align : alignof(u8);
private:
alignas(Align) u8 data[Size];
public:
constexpr ALWAYS_INLINE OutRawHolder() : data() { /* ... */ }
template
constexpr ALWAYS_INLINE uintptr_t GetAddress() const {
static_assert(Offset <= Size, "Offset <= Size");
static_assert(TypeSize <= Size, "TypeSize <= Size");
static_assert(Offset + TypeSize <= Size, "Offset + TypeSize <= Size");
return reinterpret_cast(data + Offset);
}
constexpr ALWAYS_INLINE void CopyTo(const MessageBuffer &buffer) const {
if constexpr (Size > 0) {
buffer.SetRawArray(OutIndex, data, Size);
}
}
};
template
class OutHandleHolder {
public:
static constexpr size_t NumMove = _NumMove;
static constexpr size_t NumCopy = _NumCopy;
private:
tipc::NativeHandle move_handles[NumMove];
tipc::NativeHandle copy_handles[NumCopy];
public:
ALWAYS_INLINE OutHandleHolder() { /* ... */ }
template
constexpr ALWAYS_INLINE tipc::NativeHandle *GetMoveHandlePointer() {
static_assert(Index < NumMove, "Index < NumMove");
return move_handles + Index;
}
template
constexpr ALWAYS_INLINE tipc::NativeHandle *GetCopyHandlePointer() {
static_assert(Index < NumCopy, "Index < NumCopy");
return copy_handles + Index;
}
ALWAYS_INLINE void CopyTo(const MessageBuffer &buffer) const {
#define _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(n) do { if constexpr (NumCopy > n) { buffer.SetHandle(OutIndex + n, copy_handles[n]); } } while (0)
_TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(0);
_TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(1);
_TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(2);
_TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(3);
_TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(4);
_TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(5);
_TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(6);
_TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(7);
#undef _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE
#define _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(n) do { if constexpr (NumMove > n) { buffer.SetHandle(OutIndex + NumCopy + n, move_handles[n]); } } while (0)
_TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(0);
_TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(1);
_TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(2);
_TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(3);
_TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(4);
_TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(5);
_TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(6);
_TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(7);
#undef _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE
}
};
template
struct PrintIndex;
template
class CommandProcessor {
public:
/* Useful defines. */
using ArgsType = typename CommandMeta::ArgsType;
using OutRawHolderType = OutRawHolder;
using OutHandleHolderType = OutHandleHolder;
private:
static constexpr u64 GetMessageHeaderForCheck(const MessageBuffer::MessageHeader &header) {
using Value = util::BitPack32::Field<0, BITSIZEOF(util::BitPack32)>;
const util::BitPack32 *data = header.GetData();
const u32 lower = data[0].Get();
const u32 upper = data[1].Get();
return static_cast(lower) | (static_cast(upper) << BITSIZEOF(u32));
}
static constexpr u32 GetSpecialHeaderForCheck(const MessageBuffer::SpecialHeader &header) {
using Value = util::BitPack32::Field<0, BITSIZEOF(util::BitPack32)>;
return header.GetHeader()->Get();
}
/* Argument deserialization. */
template::type>
static ALWAYS_INLINE typename std::tuple_element::type DeserializeArgumentImpl(const MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder) {
constexpr auto Info = CommandMeta::ArgumentSerializationInfos[Index];
if constexpr (Info.arg_type == ArgumentType::InData) {
/* New in rawdata. */
constexpr size_t Offset = CommandMeta::InDataOffsets[Info.in_raw_data_index];
constexpr size_t RawIndex = Offset / sizeof(u32);
static_assert(Offset == RawIndex * sizeof(u32)); /* TODO: Do unaligned data exist? */
if constexpr (!std::same_as) {
return message_buffer.GetRaw(CommandMeta::InMessageRawDataIndex + RawIndex);
} else {
return message_buffer.GetRaw(CommandMeta::InMessageRawDataIndex + RawIndex) & 1;
}
} else if constexpr (Info.arg_type == ArgumentType::OutData) {
/* New out rawdata. */
constexpr size_t Offset = CommandMeta::OutDataOffsets[Info.out_raw_data_index];
return T(out_raw_holder.template GetAddress());
} else if constexpr (Info.arg_type == ArgumentType::InHandle) {
/* New InHandle. */
if constexpr (std::same_as) {
constexpr auto HandleIndex = CommandMeta::InMessageHandleIndex + CommandMeta::NumInCopyHandles + Info.in_move_handle_index;
return T(message_buffer.GetHandle(HandleIndex));
} else if constexpr (std::same_as) {
constexpr auto HandleIndex = CommandMeta::InMessageHandleIndex + Info.in_copy_handle_index;
return T(message_buffer.GetHandle(HandleIndex));
} else {
static_assert(!std::is_same::value, "Invalid InHandle kind");
}
} else if constexpr (Info.arg_type == ArgumentType::OutHandle) {
/* New OutHandle. */
if constexpr (std::same_as) {
tipc::NativeHandle * const ptr = out_handles_holder.template GetMoveHandlePointer();
*ptr = tipc::InvalidNativeHandle;
return T(ptr);
} else if constexpr (std::same_as) {
tipc::NativeHandle * const ptr = out_handles_holder.template GetCopyHandlePointer();
*ptr = tipc::InvalidNativeHandle;
return T(ptr);
} else {
static_assert(!std::is_same::value, "Invalid OutHandle kind");
}
} else if constexpr (Info.arg_type == ArgumentType::Buffer) {
/* NOTE: There are currently no tipc commands which use buffers-with-attributes */
/* If these are added (e.g., NonSecure buffers), implement checking here? */
constexpr size_t MapAliasDescriptorSize = MessageBuffer::MapAliasDescriptor::GetDataSize();
if constexpr (Info.is_send_buffer) {
/* Input send buffer. */
constexpr auto BufferIndex = CommandMeta::InMessageBufferIndex + (Info.send_map_alias_index * MapAliasDescriptorSize / sizeof(util::BitPack32));
const MessageBuffer::MapAliasDescriptor descriptor(message_buffer, BufferIndex);
return T(descriptor.GetAddress(), descriptor.GetSize());
} else {
/* Input receive buffer. */
constexpr auto BufferIndex = CommandMeta::InMessageBufferIndex + ((CommandMeta::NumInBuffers + Info.recv_map_alias_index) * MapAliasDescriptorSize / sizeof(util::BitPack32));
const MessageBuffer::MapAliasDescriptor descriptor(message_buffer, BufferIndex);
return T(descriptor.GetAddress(), descriptor.GetSize());
}
} else if constexpr (Info.arg_type == ArgumentType::ProcessId) {
return T{ os::ProcessId{ message_buffer.GetProcessId(CommandMeta::InMessageProcessIdIndex) } };
} else {
static_assert(!std::is_same::value, "Invalid ArgumentType");
}
}
public:
static ALWAYS_INLINE Result ValidateCommandFormat(const MessageBuffer &message_buffer) {
/* Validate the message header. */
constexpr auto ExpectedMessageHeader = GetMessageHeaderForCheck(CommandMeta::InMessageHeader);
R_UNLESS(message_buffer.Get64(0) == ExpectedMessageHeader, tipc::ResultInvalidMessageFormat());
/* Validate the special header. */
if constexpr (CommandMeta::HasInSpecialHeader) {
constexpr auto ExpectedSpecialHeader = GetSpecialHeaderForCheck(CommandMeta::InSpecialHeader);
constexpr auto SpecialHeaderIndex = MessageBuffer::MessageHeader::GetDataSize() / sizeof(util::BitPack32);
R_UNLESS(message_buffer.Get32(SpecialHeaderIndex) == ExpectedSpecialHeader, tipc::ResultInvalidMessageFormat());
}
R_SUCCEED();
}
template
static ALWAYS_INLINE auto DeserializeArgument(const MessageBuffer &message_buffer, const OutRawHolderType &out_raw_holder, OutHandleHolderType &out_handles_holder) {
return DeserializeArgumentImpl(message_buffer, out_raw_holder, out_handles_holder);
}
static ALWAYS_INLINE void SerializeResults(const MessageBuffer &message_buffer, const Result &result, const OutRawHolderType &out_raw_holder, const OutHandleHolderType &out_handles_holder) {
/* Set output headers. */
message_buffer.Set(CommandMeta::OutMessageHeader);
if constexpr (CommandMeta::HasOutSpecialHeader) {
message_buffer.Set(CommandMeta::OutSpecialHeader);
}
/* Set output handles. */
out_handles_holder.CopyTo(message_buffer);
/* Set output result. */
message_buffer.Set(CommandMeta::OutMessageResultIndex, result.GetValue());
/* Set output data. */
out_raw_holder.CopyTo(message_buffer);
}
};
struct FunctionTraits {
public:
template
static std::tuple GetArgumentsImpl(R(C::*)(A...));
template
static R GetReturnImpl(R(C::*)(A...));
};
template
constexpr ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const MessageBuffer &message_buffer) {
using Return = decltype(FunctionTraits::GetReturnImpl(ServiceCommandImpl));
using TrueArgumentsTuple = decltype(FunctionTraits::GetArgumentsImpl(ServiceCommandImpl));
using CommandMeta = CommandMetaInfo<_CommmandId, TrueArgumentsTuple>;
using Processor = CommandProcessor;
/* TODO: ValidateClassType is valid? */
constexpr bool ReturnsResult = std::is_same::value;
constexpr bool ReturnsVoid = std::is_same::value;
static_assert(ReturnsResult || ReturnsVoid, "Service Commands must return Result or void.");
/* Validate that the command is valid. */
R_TRY(Processor::ValidateCommandFormat(message_buffer));
/* Deserialize arguments. */
typename Processor::OutRawHolderType out_raw_holder;
typename Processor::OutHandleHolderType out_handles_holder;
const Result command_result = [&](std::index_sequence) ALWAYS_INLINE_LAMBDA {
if constexpr (ReturnsResult) {
return (object->*ServiceCommandImpl)(Processor::template DeserializeArgument(message_buffer, out_raw_holder, out_handles_holder)...);
} else {
(object->*ServiceCommandImpl)(Processor::template DeserializeArgument(message_buffer, out_raw_holder, out_handles_holder)...);
R_SUCCEED();
}
}(std::make_index_sequence::value>());
/* Serialize output. */
Processor::SerializeResults(message_buffer, command_result, out_raw_holder, out_handles_holder);
R_SUCCEED();
}
}
#elif defined(ATMOSPHERE_OS_WINDOWS)
namespace ams::tipc::impl {
template
struct CommandMetaInfo;
template
struct CommandMetaInfo<_CommandId, std::tuple> {
public:
static constexpr size_t InMessageTotalSize = 0x40; /* TODO */
static constexpr size_t OutMessageTotalSize = 0x40; /* TODO */
};
template
class CommandProcessor {
public:
static ALWAYS_INLINE Result ValidateCommandFormat(const MessageBuffer &) {
AMS_ABORT("TODO");
}
};
template
ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const MessageBuffer &message_buffer) {
/* TODO: Is some kind of emulated serialization interesting/desirable? */
/* TIPC is generally a huge TODO. */
AMS_UNUSED(object, message_buffer);
AMS_ABORT("TIPC serialization not currently supported on Windows.");
}
}
#elif defined(ATMOSPHERE_OS_LINUX)
namespace ams::tipc::impl {
template
struct CommandMetaInfo;
template
struct CommandMetaInfo<_CommandId, std::tuple> {
public:
static constexpr size_t InMessageTotalSize = 0x40; /* TODO */
static constexpr size_t OutMessageTotalSize = 0x40; /* TODO */
};
template
class CommandProcessor {
public:
static ALWAYS_INLINE Result ValidateCommandFormat(const MessageBuffer &) {
AMS_ABORT("TODO");
}
};
template
ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const MessageBuffer &message_buffer) {
/* TODO: Is some kind of emulated serialization interesting/desirable? */
/* TIPC is generally a huge TODO. */
AMS_UNUSED(object, message_buffer);
AMS_ABORT("TIPC serialization not currently supported on Linux.");
}
}
#elif defined(ATMOSPHERE_OS_MACOS)
namespace ams::tipc::impl {
template
struct CommandMetaInfo;
template
struct CommandMetaInfo<_CommandId, std::tuple> {
public:
static constexpr size_t InMessageTotalSize = 0x40; /* TODO */
static constexpr size_t OutMessageTotalSize = 0x40; /* TODO */
};
template
class CommandProcessor {
public:
static ALWAYS_INLINE Result ValidateCommandFormat(const MessageBuffer &) {
AMS_ABORT("TODO");
}
};
template
ALWAYS_INLINE Result InvokeServiceCommandImpl(ClassType *object, const MessageBuffer &message_buffer) {
/* TODO: Is some kind of emulated serialization interesting/desirable? */
/* TIPC is generally a huge TODO. */
AMS_UNUSED(object, message_buffer);
AMS_ABORT("TIPC serialization not currently supported on macOS.");
}
}
#else
#error "Unknown OS for tipc Command serialization."
#endif