diff --git a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp
new file mode 100644
index 000000000..ba6008782
--- /dev/null
+++ b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2018-2020 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
+
+namespace ams::tipc::impl {
+
+ template
+ concept HasDefaultServiceCommandProcessor = requires (T &t, const svc::ipc::MessageBuffer &message_buffer) {
+ { t.ProcessDefaultServiceCommand(message_buffer) } -> std::same_as;
+ };
+
+ struct SyncFunctionTraits {
+ public:
+ template
+ static std::tuple GetArgsImpl(R(C::*)(A...));
+ };
+
+ template
+ using SyncFunctionArgsType = decltype(SyncFunctionTraits::GetArgsImpl(F));
+
+ #define AMS_TIPC_IMPL_DEFINE_SYNC_METHOD_HOLDER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
+ struct NAME##ArgumentsFunctionHolder { RETURN f ARGS; };
+
+ #define AMS_TIPC_IMPL_EXTRACT_SYNC_METHOD_ARGUMENTS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
+ using NAME##ArgumentsType = ::ams::tipc::impl::SyncFunctionArgsType<&NAME##ArgumentsFunctionHolder::f>;
+
+ #define AMS_TIPC_IMPL_DEFINE_INTERFACE(BASECLASS, CLASSNAME, CMD_MACRO) \
+ class CLASSNAME : public BASECLASS { \
+ private: \
+ CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_DEFINE_SYNC_METHOD_HOLDER) \
+ public: \
+ CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_EXTRACT_SYNC_METHOD_ARGUMENTS) \
+ };
+
+ #define AMS_TIPC_IMPL_DEFINE_CONCEPT_HELPERS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
+ template \
+ concept Is##CLASSNAME##__##NAME##Impl = requires (T &t, Args &&... args) { \
+ { t.NAME(std::forward(args)...) } -> std::same_as; \
+ }; \
+ \
+ template \
+ struct Is##CLASSNAME##__##NAME##Holder : std::false_type{}; \
+ \
+ template requires std::same_as, CLASSNAME::NAME##ArgumentsType> \
+ struct Is##CLASSNAME##__##NAME##Holder> : std::bool_constant>{}; \
+ \
+ template \
+ static constexpr inline bool Is##CLASSNAME##__##NAME = Is##CLASSNAME##__##NAME##Holder::value;
+
+ #define AMS_TIPC_IMPL_CHECK_CONCEPT_HELPER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
+ Is##CLASSNAME##__##NAME &&
+
+ #define AMS_TIPC_IMPL_DEFINE_CONCEPT(CLASSNAME, CMD_MACRO) \
+ CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_DEFINE_CONCEPT_HELPERS) \
+ \
+ template \
+ concept Is##CLASSNAME = CMD_MACRO(CLASSNAME, AMS_TIPC_IMPL_CHECK_CONCEPT_HELPER) true;
+
+ #define AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
+ if (constexpr u16 TipcCommandId = CMD_ID + 0x10; tag == TipcCommandId) { \
+ return this->ProcessMethodById(impl, message_buffer, fw_ver); \
+ }
+
+ #define AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST_BY_ID(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
+ if constexpr (constexpr u16 TipcCommandId = CMD_ID + 0x10; CommandId == TipcCommandId) { \
+ constexpr bool AlwaysValid = VERSION_MIN == hos::Version_Min && VERSION_MAX == hos::Version_Max; \
+ if (AlwaysValid || (VERSION_MIN <= fw_ver && fw_ver <= VERSION_MAX)) { \
+ return ::ams::tipc::impl::InvokeServiceCommandImpl(impl, message_buffer); \
+ } \
+ }
+
+ #define AMS_TIPC_DEFINE_INTERFACE_WITH_DEFAULT_BASE(NAMESPACE, INTERFACE, BASE, CMD_MACRO) \
+ namespace NAMESPACE { \
+ \
+ AMS_TIPC_IMPL_DEFINE_INTERFACE(BASE, INTERFACE, CMD_MACRO) \
+ AMS_TIPC_IMPL_DEFINE_CONCEPT(INTERFACE, CMD_MACRO) \
+ \
+ } \
+ \
+ namespace ams::tipc::impl { \
+ \
+ template \
+ class ImplTemplateBaseT<::NAMESPACE::INTERFACE, Base, ImplHolder, ImplGetter, Root> : public Base, public ImplHolder { \
+ public: \
+ template \
+ constexpr explicit ImplTemplateBaseT(Args &&...args) : ImplHolder(std::forward(args)...) { /* ... */ } \
+ private: \
+ template \
+ ALWAYS_INLINE Result ProcessDefaultMethod(ImplType *impl, const svc::ipc::MessageBuffer &message_buffer) const { \
+ /* Handle a default command. */ \
+ if constexpr (HasDefaultServiceCommandProcessor) { \
+ return impl->ProcessDefaultServiceCommand(message_buffer); \
+ } else { \
+ return tipc::ResultInvalidMethod(); \
+ } \
+ } \
+ \
+ template \
+ ALWAYS_INLINE Result ProcessMethodById(ImplType *impl, const svc::ipc::MessageBuffer &message_buffer, hos::Version fw_ver) const { \
+ CMD_MACRO(ImplType, AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST_BY_ID) \
+ \
+ return this->ProcessDefaultMethod(impl, message_buffer); \
+ } \
+ public: \
+ virtual Result ProcessRequest() override { \
+ /* Get the implementation object. */ \
+ auto * const impl = ImplGetter::GetImplPointer(static_cast(this)); \
+ \
+ /* Get the implementation type. */ \
+ using ImplType = typename std::remove_reference::type; \
+ static_assert(::NAMESPACE::Is##INTERFACE); \
+ \
+ /* Get accessor to the message buffer. */ \
+ svc::ipc::MessageBuffer message_buffer(svc::ipc::GetMessageBuffer()); \
+ \
+ /* Get decision variables. */ \
+ const auto tag = svc::ipc::MessageBuffer::MessageHeader(message_buffer).GetTag(); \
+ const auto fw_ver = hos::GetVersion(); \
+ \
+ /* Process against the command ids. */ \
+ if (false) { } \
+ CMD_MACRO(ImplType, AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST) \
+ else { \
+ return this->ProcessDefaultMethod(impl, message_buffer); \
+ } \
+ } \
+ }; \
+ \
+ }
+
+
+ #define AMS_TIPC_DEFINE_INTERFACE(NAMESPACE, INTERFACE, CMD_MACRO) \
+ AMS_TIPC_DEFINE_INTERFACE_WITH_DEFAULT_BASE(NAMESPACE, INTERFACE, ::ams::tipc::ServiceObjectBase, CMD_MACRO)
+
+ #define AMS_TIPC_METHOD_INFO_7(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES) \
+ HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, hos::Version_Min, hos::Version_Max)
+
+ #define AMS_TIPC_METHOD_INFO_8(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN) \
+ HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, hos::Version_Max)
+
+ #define AMS_TIPC_METHOD_INFO_9(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
+ HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX)
+
+ #define AMS_TIPC_METHOD_INFO_X(_, _0, _1, _2, _3, _4, _5, _6, _7, _8, FUNC, ...) FUNC
+
+ #define AMS_TIPC_METHOD_INFO(...) \
+ AMS_TIPC_METHOD_INFO_X(, ## __VA_ARGS__, AMS_TIPC_METHOD_INFO_9(__VA_ARGS__), AMS_TIPC_METHOD_INFO_8(__VA_ARGS__), AMS_TIPC_METHOD_INFO_7(__VA_ARGS__))
+
+}
diff --git a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp
index 09625e7a5..d39356b53 100644
--- a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp
+++ b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp
@@ -237,8 +237,11 @@ namespace ams::tipc::impl {
size_t out_copy_handle_index;
};
+ template
+ struct CommandMetaInfo;
+
template
- struct CommandMetaInfo {
+ struct CommandMetaInfo<_CommandId, std::tuple> {
public:
static constexpr u16 CommandId = _CommandId;
@@ -587,10 +590,22 @@ namespace ams::tipc::impl {
}
};
- template
+ 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 svc::ipc::MessageBuffer &message_buffer) {
- using CommandMeta = CommandMetaInfo<_CommmandId, Arguments...>;
- using Processor = CommandProcessor;
+ 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;
@@ -606,8 +621,6 @@ namespace ams::tipc::impl {
const Result command_result = [&](std::index_sequence) ALWAYS_INLINE_LAMBDA {
auto args_tuple = Processor::DeserializeArguments(message_buffer, out_raw_holder, out_handles_holder);
- using TrueArgumentsTuple = std::tuple;
-
if constexpr (ReturnsResult) {
return (object->*ServiceCommandImpl)(std::forward::type>(std::get(args_tuple))...);
} else {
diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object.hpp
index 2549a1a83..fe6307269 100644
--- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object.hpp
+++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_service_object.hpp
@@ -24,7 +24,8 @@ namespace ams::tipc {
template
class EmplacedImplHolderBaseGetter {
- using Type = Impl;
+ public:
+ using Type = Impl;
};
template
diff --git a/libraries/libstratosphere/source/_test/test_tipc_serializer.cpp b/libraries/libstratosphere/source/_test/test_tipc_serializer.cpp
index 07ac29545..fa04b9013 100644
--- a/libraries/libstratosphere/source/_test/test_tipc_serializer.cpp
+++ b/libraries/libstratosphere/source/_test/test_tipc_serializer.cpp
@@ -14,6 +14,16 @@
* along with this program. If not, see .
*/
#include
+#include
+
+#define AMS_TEST_I_USER_INTERFACE_INTERFACE_INFO(C, H) \
+ AMS_TIPC_METHOD_INFO(C, H, 0, Result, RegisterClient, (const tipc::ClientProcessId &client_process_id), (client_process_id)) \
+ AMS_TIPC_METHOD_INFO(C, H, 1, Result, GetServiceHandle, (tipc::OutMoveHandle out_h, sm::ServiceName service), (out_h, service)) \
+ AMS_TIPC_METHOD_INFO(C, H, 2, Result, RegisterService, (tipc::OutMoveHandle out_h, sm::ServiceName service, u32 max_sessions, bool is_light), (out_h, service, max_sessions, is_light)) \
+ AMS_TIPC_METHOD_INFO(C, H, 3, Result, UnregisterService, (sm::ServiceName service), (service))
+
+AMS_TIPC_DEFINE_INTERFACE(ams::_test::impl, IUserInterface, AMS_TEST_I_USER_INTERFACE_INTERFACE_INFO)
+
namespace ams::_test {
@@ -24,39 +34,31 @@ namespace ams::_test {
Result RegisterService(tipc::OutMoveHandle out_h, sm::ServiceName service, u32 max_sessions, bool is_light);
Result UnregisterService(sm::ServiceName service);
};
+ static_assert(impl::IsIUserInterface);
- Result TestRegisterClient(UserInterfaceFacade *facade, const svc::ipc::MessageBuffer &message_buffer) {
- return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::RegisterClient, 16, Result, UserInterfaceFacade, const tipc::ClientProcessId &>(facade, message_buffer);
- }
-
- Result TestGetServiceHandle(UserInterfaceFacade *facade, const svc::ipc::MessageBuffer &message_buffer) {
- return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::GetServiceHandle, 17, Result, UserInterfaceFacade, tipc::OutMoveHandle, sm::ServiceName>(facade, message_buffer);
- }
-
- Result TestRegisterService(UserInterfaceFacade *facade, const svc::ipc::MessageBuffer &message_buffer) {
- return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::RegisterService, 18, Result, UserInterfaceFacade, tipc::OutMoveHandle, sm::ServiceName, u32, bool>(facade, message_buffer);
- }
-
- Result TestUnregisterService(UserInterfaceFacade *facade, const svc::ipc::MessageBuffer &message_buffer) {
- return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::UnregisterService, 19, Result, UserInterfaceFacade, sm::ServiceName>(facade, message_buffer);
- }
Result TestManualDispatch(UserInterfaceFacade *facade) {
svc::ipc::MessageBuffer message_buffer(svc::ipc::GetMessageBuffer());
switch (svc::ipc::MessageBuffer::MessageHeader(message_buffer).GetTag()) {
case 16:
- return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::RegisterClient, 16, Result, UserInterfaceFacade, const tipc::ClientProcessId &>(facade, message_buffer);
+ return tipc::impl::InvokeServiceCommandImpl<16, &UserInterfaceFacade::RegisterClient, UserInterfaceFacade>(facade, message_buffer);
case 17:
- return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::GetServiceHandle, 17, Result, UserInterfaceFacade, tipc::OutMoveHandle, sm::ServiceName>(facade, message_buffer);
+ return tipc::impl::InvokeServiceCommandImpl<17, &UserInterfaceFacade::GetServiceHandle, UserInterfaceFacade>(facade, message_buffer);
case 18:
- return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::RegisterService, 18, Result, UserInterfaceFacade, tipc::OutMoveHandle, sm::ServiceName, u32, bool>(facade, message_buffer);
+ return tipc::impl::InvokeServiceCommandImpl<18, &UserInterfaceFacade::RegisterService, UserInterfaceFacade>(facade, message_buffer);
case 19:
- return tipc::impl::InvokeServiceCommandImpl<&UserInterfaceFacade::UnregisterService, 19, Result, UserInterfaceFacade, sm::ServiceName>(facade, message_buffer);
+ return tipc::impl::InvokeServiceCommandImpl<19, &UserInterfaceFacade::UnregisterService, UserInterfaceFacade>(facade, message_buffer);
default:
return tipc::ResultInvalidMethod();
}
}
+ using UserInterfaceObject = ::ams::tipc::ServiceObject;
+
+ Result TestAutomaticDispatch(UserInterfaceObject *object) {
+ return object->ProcessRequest();
+ }
+
}
\ No newline at end of file