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// This file is modified from
18// hardware/interfaces/wifi/1.0/vts/functional/wifi_hidl_call_util.h
19
20#pragma once
21
22#include <android-base/logging.h>
23#include <functional>
24#include <tuple>
25#include <type_traits>
26#include <utility>
27
28namespace {
29namespace detail {
30template <typename>
31struct functionArgSaver;
32
33// Provides a std::function that takes one argument, and a buffer
34// wherein the function will store its argument. The buffer has
35// the same type as the argument, but with const and reference
36// modifiers removed.
37template <typename ArgT>
38struct functionArgSaver<std::function<void(ArgT)>> final {
39  using StorageT = typename std::remove_const<
40      typename std::remove_reference<ArgT>::type>::type;
41
42  std::function<void(ArgT)> saveArgs = [this](ArgT arg) {
43    this->saved_values = arg;
44  };
45
46  StorageT saved_values;
47};
48
49// Provides a std::function that takes two arguments, and a buffer
50// wherein the function will store its arguments. The buffer is a
51// std::pair, whose elements have the same types as the arguments
52// (but with const and reference modifiers removed).
53template <typename Arg1T, typename Arg2T>
54struct functionArgSaver<std::function<void(Arg1T, Arg2T)>> final {
55  using StorageT =
56      std::pair<typename std::remove_const<
57                    typename std::remove_reference<Arg1T>::type>::type,
58                typename std::remove_const<
59                    typename std::remove_reference<Arg2T>::type>::type>;
60
61  std::function<void(Arg1T, Arg2T)> saveArgs = [this](Arg1T arg1, Arg2T arg2) {
62    this->saved_values = {arg1, arg2};
63  };
64
65  StorageT saved_values;
66};
67
68// Provides a std::function that takes three or more arguments, and a
69// buffer wherein the function will store its arguments. The buffer is a
70// std::tuple whose elements have the same types as the arguments (but
71// with const and reference modifiers removed).
72template <typename... ArgT>
73struct functionArgSaver<std::function<void(ArgT...)>> final {
74  using StorageT = std::tuple<typename std::remove_const<
75      typename std::remove_reference<ArgT>::type>::type...>;
76
77  std::function<void(ArgT...)> saveArgs = [this](ArgT... arg) {
78    this->saved_values = {arg...};
79  };
80
81  StorageT saved_values;
82};
83
84// Invokes |method| on |object|, providing |method| a CallbackT as the
85// final argument. Returns a copy of the parameters that |method| provided
86// to CallbackT. (The parameters are returned by value.)
87template <typename CallbackT, typename MethodT, typename ObjectT,
88          typename... ArgT>
89std::pair<typename functionArgSaver<CallbackT>::StorageT, bool> invokeMethod(
90    MethodT method, ObjectT object, ArgT&&... methodArg) {
91  functionArgSaver<CallbackT> result_buffer;
92  const auto& res = ((*object).*method)(std::forward<ArgT>(methodArg)...,
93                                        result_buffer.saveArgs);
94  bool transportStatus = true;
95  if (!res.isOk()) {
96    LOG(ERROR) << " Transport failed " << res.description();
97    transportStatus = false;
98  }
99  return std::make_pair(result_buffer.saved_values, transportStatus);
100}
101}  // namespace detail
102}  // namespace
103
104// Invokes |method| on |strong_pointer|, passing provided arguments through to
105// |method|.
106//
107// Returns either:
108// - A copy of the result callback parameter (for callbacks with a single
109//   parameter), OR
110// - A pair containing a copy of the result callback parameters (for callbacks
111//   with two parameters), OR
112// - A tuple containing a copy of the result callback paramters (for callbacks
113//   with three or more parameters).
114//
115// Example usage:
116//   EXPECT_EQ(WifiStatusCode::SUCCESS,
117//       HIDL_INVOKE(strong_pointer, methodReturningWifiStatus).code);
118//   EXPECT_EQ(WifiStatusCode::SUCCESS,
119//       HIDL_INVOKE(strong_pointer, methodReturningWifiStatusAndOneMore)
120//         .first.code);
121//   EXPECT_EQ(WifiStatusCode::SUCCESS, std::get<0>(
122//       HIDL_INVOKE(strong_pointer, methodReturningWifiStatusAndTwoMore))
123//         .code);
124#define HIDL_INVOKE(strong_pointer, method, ...)                            \
125  (detail::invokeMethod<                                                    \
126      std::remove_reference<decltype(*strong_pointer)>::type::method##_cb>( \
127      &std::remove_reference<decltype(*strong_pointer)>::type::method,      \
128      strong_pointer, ##__VA_ARGS__))
129