#ifndef RTORRENT_RPC_COMMAND_H #define RTORRENT_RPC_COMMAND_H #include #include #include #include #include #include // Move into config.h or something. namespace core { class Download; } namespace rpc { template struct target_wrapper { typedef Target target_type; typedef Target cleaned_type; }; template <> struct target_wrapper { struct no_type {}; typedef void target_type; typedef no_type* cleaned_type; }; template struct rt_triple : private std::pair { typedef std::pair base_type; typedef T3 third_type; using base_type::first; using base_type::second; using typename base_type::first_type; using typename base_type::second_type; T3 third; rt_triple() : base_type(), third() {} rt_triple(const T1& a, const T2& b) : base_type(a, b), third() {} rt_triple(const T1& a, const T2& b, const T3& c) : base_type(a, b), third(c) {} rt_triple(const base_type& b) : base_type(b), third() {} rt_triple(const rt_triple& src) : base_type(src.first, src.second), third(src.third) {} }; class command_base; using target_type = rt_triple; using base_function = std::function; using command_base_call_type = const torrent::Object (command_base*, target_type, const torrent::Object&); template struct command_base_is_valid {}; template struct command_base_is_type {}; class command_base { public: typedef torrent::Object::value_type value_type; typedef torrent::Object::string_type string_type; typedef torrent::Object::list_type list_type; typedef torrent::Object::map_type map_type; typedef torrent::Object::key_type key_type; typedef const torrent::Object (*generic_slot) (command_base*, const torrent::Object&); typedef const torrent::Object (*cleaned_slot) (command_base*, target_wrapper::cleaned_type, const torrent::Object&); typedef const torrent::Object (*any_slot) (command_base*, target_type, const torrent::Object&); typedef const torrent::Object (*download_slot) (command_base*, core::Download*, const torrent::Object&); typedef const torrent::Object (*file_slot) (command_base*, torrent::File*, const torrent::Object&); typedef const torrent::Object (*file_itr_slot) (command_base*, torrent::FileListIterator*, const torrent::Object&); typedef const torrent::Object (*peer_slot) (command_base*, torrent::Peer*, const torrent::Object&); typedef const torrent::Object (*tracker_slot) (command_base*, torrent::tracker::Tracker*, const torrent::Object&); typedef const torrent::Object (*download_pair_slot) (command_base*, core::Download*, core::Download*, const torrent::Object&); static constexpr int target_generic = 0; static constexpr int target_any = 1; static constexpr int target_download = 2; static constexpr int target_peer = 3; static constexpr int target_tracker = 4; static constexpr int target_file = 5; static constexpr int target_file_itr = 6; static constexpr int target_download_pair = 7; static constexpr unsigned int max_arguments = 10; static constexpr std::size_t optimal_alignment = std::max(alignof(std::max_align_t), alignof(base_function)); struct stack_type { torrent::Object* begin() { return reinterpret_cast(buffer); } torrent::Object* end() { return reinterpret_cast(buffer) + max_arguments; } const torrent::Object* begin() const { return reinterpret_cast(buffer); } const torrent::Object* end() const { return reinterpret_cast(buffer) + max_arguments; } torrent::Object& operator [] (unsigned int idx) { return *(begin() + idx); } const torrent::Object& operator [] (unsigned int idx) const { return *(begin() + idx); } static stack_type* from_data(char* data) { return reinterpret_cast(data); } char buffer[sizeof(torrent::Object) * max_arguments]; }; command_base() : m_copy_helper(nullptr), m_dest_helper(nullptr) {} command_base(const command_base& src) { m_copy_helper = src.m_copy_helper; m_dest_helper = src.m_dest_helper; if (src.m_copy_helper) src.m_copy_helper(t_pod, src.t_pod); } command_base& operator=(const command_base& src) { if (this != &src) { if (m_dest_helper) m_dest_helper(t_pod); m_copy_helper = src.m_copy_helper; m_dest_helper = src.m_dest_helper; if (src.m_copy_helper) src.m_copy_helper(t_pod, src.t_pod); } return *this; } command_base(command_base&& src) noexcept { m_copy_helper = src.m_copy_helper; m_dest_helper = src.m_dest_helper; if (src.m_copy_helper) src.m_copy_helper(t_pod, src.t_pod); } command_base& operator=(command_base&& src) noexcept { if (this != &src) { if (m_dest_helper) m_dest_helper(t_pod); m_copy_helper = src.m_copy_helper; m_dest_helper = src.m_dest_helper; if (src.m_copy_helper) src.m_copy_helper(t_pod, src.t_pod); } return *this; } ~command_base() { if (m_dest_helper) m_dest_helper(t_pod); } static torrent::Object* argument(unsigned int index) { return current_stack.begin() + index; } static torrent::Object& argument_ref(unsigned int index) { return *(current_stack.begin() + index); } static stack_type current_stack; static torrent::Object* stack_begin() { return current_stack.begin(); } static torrent::Object* stack_end() { return current_stack.end(); } static torrent::Object* push_stack(const torrent::Object::list_type& args, stack_type* stack); static torrent::Object* push_stack(const torrent::Object* first_arg, const torrent::Object* last_arg, stack_type* stack); static void pop_stack(stack_type* stack, torrent::Object* last_stack); template void set_function(T s, [[maybe_unused]] int value = command_base_is_valid::value) { static_assert(sizeof(T) <= sizeof(t_pod), "t_pod storage overflow"); static_assert(optimal_alignment >= alignof(T), "t_pod alignment insufficient for type"); if (m_dest_helper) m_dest_helper(t_pod); ::new (t_pod) T(std::move(s)); m_copy_helper = [](void* dest, const void* src) { ::new (dest) T(*static_cast(src)); }; m_dest_helper = [](void* ptr) { static_cast(ptr)->~T(); }; } template void set_function_2(typename command_base_is_type::type s, [[maybe_unused]] int value = command_base_is_valid::type>::value) { set_function::type>(std::move(s)); } template tmpl& _pod() { return reinterpret_cast(t_pod); } template const tmpl& _pod() const { return reinterpret_cast(t_pod); } template static const torrent::Object _call(command_base* cmd, target_type target, Args args); protected: using copy_fn_t = void (*)(void* dest, const void* src); using dest_fn_t = void (*)(void* ptr); alignas(optimal_alignment) char t_pod[sizeof(base_function)]; copy_fn_t m_copy_helper; dest_fn_t m_dest_helper; }; template struct target_type_id { }; template inline bool is_target_compatible(const target_type& target) { return target.first == target_type_id::value; } inline bool is_target_pair(const target_type& target) { return target.first >= command_base::target_download_pair; } template inline T get_target_cast(target_type target, [[maybe_unused]] int type = target_type_id::value) { return (T)target.second; } inline target_type get_target_left(const target_type& target) { return target_type(target.first - 5, target.second); } inline target_type get_target_right(const target_type& target) { return target_type(target.first - 5, target.third); } } #include "command_impl.h" namespace rpc { template inline const torrent::Object command_base::_call(command_base* cmd, target_type target, Args args) { return static_cast(cmd)->_pod()(get_target_cast(target), args); } #define COMMAND_BASE_TEMPLATE_TYPE(func_type, func_parm) \ template ::proper_type> struct func_type { typedef std::function type; }; \ \ template <> struct command_base_is_valid::type> { static const int value = 1; }; \ template <> struct command_base_is_valid::type> { static const int value = 1; }; \ template <> struct command_base_is_valid::type> { static const int value = 1; }; \ template <> struct command_base_is_valid::type> { static const int value = 1; }; \ template <> struct command_base_is_valid::type> { static const int value = 1; }; \ template <> struct command_base_is_valid::type> { static const int value = 1; }; COMMAND_BASE_TEMPLATE_TYPE(command_function, torrent::Object (T, const torrent::Object&)); COMMAND_BASE_TEMPLATE_TYPE(command_value_function, torrent::Object (T, const torrent::Object::value_type&)); COMMAND_BASE_TEMPLATE_TYPE(command_string_function, torrent::Object (T, const std::string&)); COMMAND_BASE_TEMPLATE_TYPE(command_list_function, torrent::Object (T, const torrent::Object::list_type&)); #define COMMAND_BASE_TEMPLATE_CALL(func_name, func_type) \ template const torrent::Object func_name(command_base* rawCommand, target_type target, const torrent::Object& args); \ \ template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; \ template <> struct command_base_is_type > { static const int value = 1; typedef func_type::type type; }; COMMAND_BASE_TEMPLATE_CALL(command_base_call, command_function); COMMAND_BASE_TEMPLATE_CALL(command_base_call_value, command_value_function); COMMAND_BASE_TEMPLATE_CALL(command_base_call_value_kb, command_value_function); COMMAND_BASE_TEMPLATE_CALL(command_base_call_string, command_string_function); COMMAND_BASE_TEMPLATE_CALL(command_base_call_list, command_list_function); } #endif