1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <functional>
20 #include <tuple>
21 #include <type_traits>
22 #include <utility>
23 
24 namespace {
25 namespace detail {
26 template <typename>
27 struct functionArgSaver;
28 
29 // Provides a std::function that takes one argument, and a buffer
30 // wherein the function will store its argument. The buffer has
31 // the same type as the argument, but with const and reference
32 // modifiers removed.
33 template <typename ArgT>
34 struct functionArgSaver<std::function<void(ArgT)>> final {
35     using StorageT = typename std::remove_const<
36         typename std::remove_reference<ArgT>::type>::type;
37 
38     std::function<void(ArgT)> saveArgs = [this](ArgT arg) {
39         this->saved_values = arg;
40     };
41 
42     StorageT saved_values;
43 };
44 
45 // Provides a std::function that takes two arguments, and a buffer
46 // wherein the function will store its arguments. The buffer is a
47 // std::pair, whose elements have the same types as the arguments
48 // (but with const and reference modifiers removed).
49 template <typename Arg1T, typename Arg2T>
50 struct functionArgSaver<std::function<void(Arg1T, Arg2T)>> final {
51     using StorageT =
52         std::pair<typename std::remove_const<
53                       typename std::remove_reference<Arg1T>::type>::type,
54                   typename std::remove_const<
55                       typename std::remove_reference<Arg2T>::type>::type>;
56 
57     std::function<void(Arg1T, Arg2T)> saveArgs = [this](Arg1T arg1,
58                                                         Arg2T arg2) {
59         this->saved_values = {arg1, arg2};
60     };
61 
62     StorageT saved_values;
63 };
64 
65 // Provides a std::function that takes three or more arguments, and a
66 // buffer wherein the function will store its arguments. The buffer is a
67 // std::tuple whose elements have the same types as the arguments (but
68 // with const and reference modifiers removed).
69 template <typename... ArgT>
70 struct functionArgSaver<std::function<void(ArgT...)>> final {
71     using StorageT = std::tuple<typename std::remove_const<
72         typename std::remove_reference<ArgT>::type>::type...>;
73 
74     std::function<void(ArgT...)> saveArgs = [this](ArgT... arg) {
75         this->saved_values = {arg...};
76     };
77 
78     StorageT saved_values;
79 };
80 
81 // Invokes |method| on |object|, providing |method| a CallbackT as the
82 // final argument. Returns a copy of the parameters that |method| provided
83 // to CallbackT. (The parameters are returned by value.)
84 template <typename CallbackT, typename MethodT, typename ObjectT,
85           typename... ArgT>
86 typename functionArgSaver<CallbackT>::StorageT invokeMethod(
87     MethodT method, ObjectT object, ArgT&&... methodArg) {
88     functionArgSaver<CallbackT> result_buffer;
89     const auto& res = ((*object).*method)(std::forward<ArgT>(methodArg)...,
90                                           result_buffer.saveArgs);
91     EXPECT_TRUE(res.isOk());
92     return result_buffer.saved_values;
93 }
94 }  // namespace detail
95 }  // namespace
96 
97 // Invokes |method| on |strong_pointer|, passing provided arguments through to
98 // |method|.
99 //
100 // Returns either:
101 // - A copy of the result callback parameter (for callbacks with a single
102 //   parameter), OR
103 // - A pair containing a copy of the result callback parameters (for callbacks
104 //   with two parameters), OR
105 // - A tuple containing a copy of the result callback paramters (for callbacks
106 //   with three or more parameters).
107 //
108 // Example usage:
109 //   EXPECT_EQ(WifiStatusCode::SUCCESS,
110 //       HIDL_INVOKE(strong_pointer, methodReturningWifiStatus).code);
111 //   EXPECT_EQ(WifiStatusCode::SUCCESS,
112 //       HIDL_INVOKE(strong_pointer, methodReturningWifiStatusAndOneMore)
113 //         .first.code);
114 //   EXPECT_EQ(WifiStatusCode::SUCCESS, std::get<0>(
115 //       HIDL_INVOKE(strong_pointer, methodReturningWifiStatusAndTwoMore))
116 //         .code);
117 #define HIDL_INVOKE(strong_pointer, method, ...)                              \
118     (detail::invokeMethod<                                                    \
119         std::remove_reference<decltype(*strong_pointer)>::type::method##_cb>( \
120         &std::remove_reference<decltype(*strong_pointer)>::type::method,      \
121         strong_pointer, ##__VA_ARGS__))
122