1 /* 2 * Copyright (C) 2021 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 /** 18 * @addtogroup NdkBinder 19 * @{ 20 */ 21 22 /** 23 * @file binder_to_string.h 24 * @brief Helper for parcelable. 25 */ 26 27 #pragma once 28 29 #include <codecvt> 30 #include <locale> 31 #include <memory> 32 #include <optional> 33 #include <sstream> 34 #include <string> 35 #include <type_traits> 36 37 #if __has_include(<utils/StrongPointer.h>) 38 #include <utils/StrongPointer.h> 39 #define HAS_STRONG_POINTER 40 #endif 41 42 #if __has_include(<utils/String16.h>) 43 #include <utils/String16.h> 44 #define HAS_STRING16 45 #endif 46 47 #if __has_include(<android/binder_ibinder.h>) 48 #include <android/binder_auto_utils.h> 49 #include <android/binder_interface_utils.h> 50 #include <android/binder_parcelable_utils.h> 51 #define HAS_NDK_INTERFACE 52 #else 53 #include <binder/IBinder.h> 54 #include <binder/IInterface.h> 55 #include <binder/ParcelFileDescriptor.h> 56 #include <binder/ParcelableHolder.h> 57 #endif //_has_include 58 59 namespace android { 60 namespace internal { 61 62 // ToString is a utility to generate string representation for various AIDL-supported types. 63 template <typename _T> 64 std::string ToString(const _T& t); 65 66 namespace details { 67 68 // Truthy if _T has toString() method. 69 template <typename _T> 70 class HasToStringMethod { 71 template <typename _U> 72 static auto _test(int) -> decltype(std::declval<_U>().toString(), std::true_type()); 73 template <typename _U> 74 static std::false_type _test(...); 75 76 public: 77 enum { value = decltype(_test<_T>(0))::value }; 78 }; 79 80 // Truthy if _T has a overloaded toString(T) 81 template <typename _T> 82 class HasToStringFunction { 83 template <typename _U> 84 static auto _test(int) -> decltype(toString(std::declval<_U>()), std::true_type()); 85 template <typename _U> 86 static std::false_type _test(...); 87 88 public: 89 enum { value = decltype(_test<_T>(0))::value }; 90 }; 91 92 template <typename T, template <typename...> typename U> 93 struct IsInstantiationOf : std::false_type {}; 94 95 template <template <typename...> typename U, typename... Args> 96 struct IsInstantiationOf<U<Args...>, U> : std::true_type {}; 97 98 // Truthy if _T is like a pointer: one of sp/optional/shared_ptr 99 template <typename _T> 100 class IsPointerLike { 101 template <typename _U> 102 static std::enable_if_t< 103 #ifdef HAS_STRONG_POINTER 104 IsInstantiationOf<_U, sp>::value || // for IBinder and interface types in the C++ 105 // backend 106 #endif 107 IsInstantiationOf<_U, std::optional>::value || // for @nullable types in the 108 // C++/NDK backends 109 IsInstantiationOf<_U, std::shared_ptr>::value, // for interface types in the 110 // NDK backends 111 112 std::true_type> 113 _test(int); 114 template <typename _U> 115 static std::false_type _test(...); 116 117 public: 118 enum { value = decltype(_test<_T>(0))::value }; 119 }; 120 121 // Truthy if _T is like a container 122 template <typename _T> 123 class IsIterable { 124 template <typename _U> 125 static auto _test(int) 126 -> decltype(begin(std::declval<_U>()), end(std::declval<_U>()), std::true_type()); 127 template <typename _U> 128 static std::false_type _test(...); 129 130 public: 131 enum { value = decltype(_test<_T>(0))::value }; 132 }; 133 134 template <typename _T> 135 class ToEmptyString { 136 template <typename _U> 137 static std::enable_if_t< 138 #ifdef HAS_NDK_INTERFACE 139 std::is_base_of_v<::ndk::ICInterface, _U> || 140 std::is_same_v<::ndk::AParcelableHolder, _U> 141 #else 142 std::is_base_of_v<IInterface, _U> || std::is_same_v<IBinder, _U> || 143 std::is_same_v<os::ParcelFileDescriptor, _U> || 144 std::is_same_v<os::ParcelableHolder, _U> 145 #endif 146 , 147 std::true_type> 148 _test(int); 149 template <typename _U> 150 static std::false_type _test(...); 151 152 public: 153 enum { value = decltype(_test<_T>(0))::value }; 154 }; 155 156 } // namespace details 157 158 template <typename _T> 159 std::string ToString(const _T& t) { 160 if constexpr (details::ToEmptyString<_T>::value) { 161 return ""; 162 } else if constexpr (std::is_same_v<bool, _T>) { 163 return t ? "true" : "false"; 164 } else if constexpr (std::is_same_v<char16_t, _T>) { 165 return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>().to_bytes(t); 166 } else if constexpr (std::is_arithmetic_v<_T>) { 167 return std::to_string(t); 168 } else if constexpr (std::is_same_v<std::string, _T>) { 169 return t; 170 #ifdef HAS_NDK_INTERFACE 171 } else if constexpr (std::is_same_v<::ndk::SpAIBinder, _T>) { 172 return (t.get() == nullptr) ? "(null)" : ""; 173 } else if constexpr (std::is_same_v<::ndk::ScopedFileDescriptor, _T>) { 174 return (t.get() == -1) ? "(null)" : ""; 175 #endif 176 #ifdef HAS_STRING16 177 } else if constexpr (std::is_same_v<String16, _T>) { 178 std::stringstream out; 179 out << t; 180 return out.str(); 181 #endif 182 } else if constexpr (details::IsPointerLike<_T>::value || std::is_pointer_v<_T>) { 183 if (!t) return "(null)"; 184 std::stringstream out; 185 out << ToString(*t); 186 return out.str(); 187 } else if constexpr (details::HasToStringMethod<_T>::value) { 188 return t.toString(); 189 } else if constexpr (details::HasToStringFunction<_T>::value) { 190 return toString(t); 191 } else if constexpr (details::IsIterable<_T>::value) { 192 std::stringstream out; 193 bool first = true; 194 out << "["; 195 for (const auto& e : t) { 196 if (first) { 197 first = false; 198 } else { 199 out << ", "; 200 } 201 // Use explicit type parameter in case deref of iterator has different type 202 // e.g. vector<bool> 203 out << ToString<typename _T::value_type>(e); 204 } 205 out << "]"; 206 return out.str(); 207 } else { 208 return "{no toString() implemented}"; 209 } 210 } 211 212 } // namespace internal 213 } // namespace android 214 215 /** @} */ 216