| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @addtogroup NdkBinder |
| * @{ |
| */ |
| |
| /** |
| * @file binder_parcel_utils.h |
| * @brief A collection of helper wrappers for AParcel. |
| */ |
| |
| #pragma once |
| |
| #include <android/binder_auto_utils.h> |
| #include <android/binder_interface_utils.h> |
| #include <android/binder_internal_logging.h> |
| #include <android/binder_parcel.h> |
| |
| #include <array> |
| #include <optional> |
| #include <string> |
| #include <type_traits> |
| #include <vector> |
| |
| namespace ndk { |
| |
| namespace { |
| template <typename Test, template <typename...> class Ref> |
| struct is_specialization : std::false_type {}; |
| |
| template <template <typename...> class Ref, typename... Args> |
| struct is_specialization<Ref<Args...>, Ref> : std::true_type {}; |
| |
| template <typename Test, template <typename...> class Ref> |
| static inline constexpr bool is_specialization_v = is_specialization<Test, Ref>::value; |
| |
| // Get the first template type from a container, the T from MyClass<T, ...>. |
| template <typename T> |
| struct first_template_type { |
| using type = void; |
| }; |
| |
| template <template <typename...> class V, typename T, typename... Args> |
| struct first_template_type<V<T, Args...>> { |
| using type = T; |
| }; |
| |
| template <typename T> |
| using first_template_type_t = typename first_template_type<T>::type; |
| |
| // Tells if T represents NDK interface (shared_ptr<ICInterface-derived>) |
| template <typename T> |
| static inline constexpr bool is_interface_v = is_specialization_v<T, std::shared_ptr>&& |
| std::is_base_of_v<::ndk::ICInterface, first_template_type_t<T>>; |
| |
| // Tells if T represents NDK parcelable with readFromParcel/writeToParcel methods defined |
| template <typename T, typename = void> |
| struct is_parcelable : std::false_type {}; |
| |
| template <typename T> |
| struct is_parcelable< |
| T, std::void_t<decltype(std::declval<T>().readFromParcel(std::declval<const AParcel*>())), |
| decltype(std::declval<T>().writeToParcel(std::declval<AParcel*>()))>> |
| : std::true_type {}; |
| |
| template <typename T> |
| static inline constexpr bool is_parcelable_v = is_parcelable<T>::value; |
| |
| // Tells if T represents nullable NDK parcelable (optional<parcelable> or unique_ptr<parcelable>) |
| template <typename T> |
| static inline constexpr bool is_nullable_parcelable_v = is_parcelable_v<first_template_type_t<T>> && |
| (is_specialization_v<T, std::optional> || |
| is_specialization_v<T, std::unique_ptr>); |
| |
| // Tells if T is a fixed-size array. |
| template <typename T> |
| struct is_fixed_array : std::false_type {}; |
| |
| template <typename T, size_t N> |
| struct is_fixed_array<std::array<T, N>> : std::true_type {}; |
| |
| template <typename T> |
| static inline constexpr bool is_fixed_array_v = is_fixed_array<T>::value; |
| |
| template <typename T> |
| static inline constexpr bool dependent_false_v = false; |
| } // namespace |
| |
| /** |
| * This checks the length against the array size and retrieves the buffer. No allocation required. |
| */ |
| template <typename T, size_t N> |
| static inline bool AParcel_stdArrayAllocator(void* arrayData, int32_t length, T** outBuffer) { |
| if (length < 0) return false; |
| |
| if (length != static_cast<int32_t>(N)) { |
| return false; |
| } |
| |
| std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrayData); |
| *outBuffer = arr->data(); |
| return true; |
| } |
| |
| /** |
| * This checks the length against the array size and retrieves the buffer. No allocation required. |
| */ |
| template <typename T, size_t N> |
| static inline bool AParcel_nullableStdArrayAllocator(void* arrayData, int32_t length, |
| T** outBuffer) { |
| std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrayData); |
| if (length < 0) { |
| *arr = std::nullopt; |
| return true; |
| } |
| |
| if (length != static_cast<int32_t>(N)) { |
| return false; |
| } |
| |
| arr->emplace(); |
| *outBuffer = (*arr)->data(); |
| return true; |
| } |
| |
| /** |
| * This checks the length against the array size. No allocation required. |
| */ |
| template <size_t N> |
| static inline bool AParcel_stdArrayExternalAllocator(void* arrayData, int32_t length) { |
| (void)arrayData; |
| return length == static_cast<int32_t>(N); |
| } |
| |
| /** |
| * This checks the length against the array size. No allocation required. |
| */ |
| template <typename T, size_t N> |
| static inline bool AParcel_nullableStdArrayExternalAllocator(void* arrayData, int32_t length) { |
| std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrayData); |
| |
| if (length < 0) { |
| *arr = std::nullopt; |
| return true; |
| } |
| |
| if (length != static_cast<int32_t>(N)) { |
| return false; |
| } |
| |
| arr->emplace(); |
| return true; |
| } |
| |
| /** |
| * This retrieves and allocates a vector to size 'length' and returns the underlying buffer. |
| */ |
| template <typename T> |
| static inline bool AParcel_stdVectorAllocator(void* vectorData, int32_t length, T** outBuffer) { |
| if (length < 0) return false; |
| |
| std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData); |
| if (static_cast<size_t>(length) > vec->max_size()) return false; |
| |
| vec->resize(static_cast<size_t>(length)); |
| *outBuffer = vec->data(); |
| return true; |
| } |
| |
| /** |
| * This retrieves and allocates a vector to size 'length' and returns the underlying buffer. |
| */ |
| template <typename T> |
| static inline bool AParcel_nullableStdVectorAllocator(void* vectorData, int32_t length, |
| T** outBuffer) { |
| std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData); |
| |
| if (length < 0) { |
| *vec = std::nullopt; |
| return true; |
| } |
| |
| *vec = std::optional<std::vector<T>>(std::vector<T>{}); |
| |
| if (static_cast<size_t>(length) > (*vec)->max_size()) return false; |
| (*vec)->resize(static_cast<size_t>(length)); |
| |
| *outBuffer = (*vec)->data(); |
| return true; |
| } |
| |
| /** |
| * This allocates a vector to size 'length' and returns whether the allocation is successful. |
| * |
| * See also AParcel_stdVectorAllocator. Types used with this allocator have their sizes defined |
| * externally with respect to the NDK, and that size information is not passed into the NDK. |
| * Instead, it is used in cases where callbacks are used. Note that when this allocator is used, |
| * null arrays are not supported. |
| * |
| * See AParcel_readVector(const AParcel* parcel, std::vector<bool>) |
| * See AParcel_readVector(const AParcel* parcel, std::vector<std::string>) |
| */ |
| template <typename T> |
| static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, int32_t length) { |
| if (length < 0) return false; |
| |
| std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData); |
| if (static_cast<size_t>(length) > vec->max_size()) return false; |
| |
| vec->resize(static_cast<size_t>(length)); |
| return true; |
| } |
| |
| /** |
| * This allocates a vector to size 'length' and returns whether the allocation is successful. |
| * |
| * See also AParcel_stdVectorAllocator. Types used with this allocator have their sizes defined |
| * externally with respect to the NDK, and that size information is not passed into the NDK. |
| * Instead, it is used in cases where callbacks are used. Note, when this allocator is used, |
| * the vector itself can be nullable. |
| * |
| * See AParcel_readVector(const AParcel* parcel, |
| * std::optional<std::vector<std::optional<std::string>>>) |
| */ |
| template <typename T> |
| static inline bool AParcel_nullableStdVectorExternalAllocator(void* vectorData, int32_t length) { |
| std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData); |
| |
| if (length < 0) { |
| *vec = std::nullopt; |
| return true; |
| } |
| |
| *vec = std::optional<std::vector<T>>(std::vector<T>{}); |
| |
| if (static_cast<size_t>(length) > (*vec)->max_size()) return false; |
| (*vec)->resize(static_cast<size_t>(length)); |
| |
| return true; |
| } |
| |
| /** |
| * This retrieves the underlying value in a vector which may not be contiguous at index from a |
| * corresponding vectorData. |
| */ |
| template <typename T> |
| static inline T AParcel_stdVectorGetter(const void* vectorData, size_t index) { |
| const std::vector<T>* vec = static_cast<const std::vector<T>*>(vectorData); |
| return (*vec)[index]; |
| } |
| |
| /** |
| * This sets the underlying value in a corresponding vectorData which may not be contiguous at |
| * index. |
| */ |
| template <typename T> |
| static inline void AParcel_stdVectorSetter(void* vectorData, size_t index, T value) { |
| std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData); |
| (*vec)[index] = value; |
| } |
| |
| /** |
| * This sets the underlying value in a corresponding vectorData which may not be contiguous at |
| * index. |
| */ |
| template <typename T> |
| static inline void AParcel_nullableStdVectorSetter(void* vectorData, size_t index, T value) { |
| std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData); |
| vec->value()[index] = value; |
| } |
| |
| /** |
| * Convenience method to write a nullable strong binder. |
| */ |
| static inline binder_status_t AParcel_writeNullableStrongBinder(AParcel* parcel, |
| const SpAIBinder& binder) { |
| return AParcel_writeStrongBinder(parcel, binder.get()); |
| } |
| |
| /** |
| * Convenience method to read a nullable strong binder. |
| */ |
| static inline binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, |
| SpAIBinder* binder) { |
| AIBinder* readBinder; |
| binder_status_t status = AParcel_readStrongBinder(parcel, &readBinder); |
| if (status == STATUS_OK) { |
| binder->set(readBinder); |
| } |
| return status; |
| } |
| |
| /** |
| * Convenience method to write a strong binder but return an error if it is null. |
| */ |
| static inline binder_status_t AParcel_writeRequiredStrongBinder(AParcel* parcel, |
| const SpAIBinder& binder) { |
| if (binder.get() == nullptr) { |
| syslog(LOG_ERR, "Passing null binder object as non-@nullable AIDL IBinder"); |
| return STATUS_UNEXPECTED_NULL; |
| } |
| return AParcel_writeStrongBinder(parcel, binder.get()); |
| } |
| |
| /** |
| * Convenience method to read a strong binder but return an error if it is null. |
| */ |
| static inline binder_status_t AParcel_readRequiredStrongBinder(const AParcel* parcel, |
| SpAIBinder* binder) { |
| AIBinder* readBinder; |
| binder_status_t ret = AParcel_readStrongBinder(parcel, &readBinder); |
| if (ret == STATUS_OK) { |
| if (readBinder == nullptr) { |
| return STATUS_UNEXPECTED_NULL; |
| } |
| |
| binder->set(readBinder); |
| } |
| return ret; |
| } |
| |
| /** |
| * Convenience method to write a ParcelFileDescriptor where -1 represents a null value. |
| */ |
| static inline binder_status_t AParcel_writeNullableParcelFileDescriptor( |
| AParcel* parcel, const ScopedFileDescriptor& fd) { |
| return AParcel_writeParcelFileDescriptor(parcel, fd.get()); |
| } |
| |
| /** |
| * Convenience method to read a ParcelFileDescriptor where -1 represents a null value. |
| */ |
| static inline binder_status_t AParcel_readNullableParcelFileDescriptor(const AParcel* parcel, |
| ScopedFileDescriptor* fd) { |
| int readFd; |
| binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd); |
| if (status == STATUS_OK) { |
| fd->set(readFd); |
| } |
| return status; |
| } |
| |
| /** |
| * Convenience method to write a valid ParcelFileDescriptor. |
| */ |
| static inline binder_status_t AParcel_writeRequiredParcelFileDescriptor( |
| AParcel* parcel, const ScopedFileDescriptor& fd) { |
| if (fd.get() < 0) { |
| syslog(LOG_ERR, "Passing -1 file descriptor as non-@nullable AIDL ParcelFileDescriptor"); |
| return STATUS_UNEXPECTED_NULL; |
| } |
| return AParcel_writeParcelFileDescriptor(parcel, fd.get()); |
| } |
| |
| /** |
| * Convenience method to read a valid ParcelFileDescriptor. |
| */ |
| static inline binder_status_t AParcel_readRequiredParcelFileDescriptor(const AParcel* parcel, |
| ScopedFileDescriptor* fd) { |
| int readFd; |
| binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd); |
| if (status == STATUS_OK) { |
| if (readFd < 0) { |
| return STATUS_UNEXPECTED_NULL; |
| } |
| fd->set(readFd); |
| } |
| return status; |
| } |
| |
| /** |
| * Allocates a std::string to length and returns the underlying buffer. For use with |
| * AParcel_readString. See use below in AParcel_readString(const AParcel*, std::string*). |
| */ |
| static inline bool AParcel_stdStringAllocator(void* stringData, int32_t length, char** buffer) { |
| if (length <= 0) return false; |
| |
| std::string* str = static_cast<std::string*>(stringData); |
| str->resize(static_cast<size_t>(length) - 1); |
| *buffer = &(*str)[0]; |
| return true; |
| } |
| |
| /** |
| * Allocates a string in a std::optional<std::string> to size 'length' (or to std::nullopt when |
| * length is -1) and returns the underlying buffer. For use with AParcel_readString. See use below |
| * in AParcel_readString(const AParcel*, std::optional<std::string>*). |
| */ |
| static inline bool AParcel_nullableStdStringAllocator(void* stringData, int32_t length, |
| char** buffer) { |
| if (length == 0) return false; |
| |
| std::optional<std::string>* str = static_cast<std::optional<std::string>*>(stringData); |
| |
| if (length < 0) { |
| *str = std::nullopt; |
| return true; |
| } |
| |
| *str = std::optional<std::string>(std::string{}); |
| (*str)->resize(static_cast<size_t>(length) - 1); |
| *buffer = &(**str)[0]; |
| return true; |
| } |
| |
| /** |
| * Allocates a std::string inside of a std::vector<std::string> at index 'index' to size 'length'. |
| */ |
| static inline bool AParcel_stdVectorStringElementAllocator(void* vectorData, size_t index, |
| int32_t length, char** buffer) { |
| std::vector<std::string>* vec = static_cast<std::vector<std::string>*>(vectorData); |
| std::string& element = vec->at(index); |
| return AParcel_stdStringAllocator(static_cast<void*>(&element), length, buffer); |
| } |
| |
| /** |
| * This gets the length and buffer of a std::string inside of a std::vector<std::string> at index |
| * index. |
| */ |
| static inline const char* AParcel_stdVectorStringElementGetter(const void* vectorData, size_t index, |
| int32_t* outLength) { |
| const std::vector<std::string>* vec = static_cast<const std::vector<std::string>*>(vectorData); |
| const std::string& element = vec->at(index); |
| |
| *outLength = static_cast<int32_t>(element.size()); |
| return element.c_str(); |
| } |
| |
| /** |
| * Allocates a string in a std::optional<std::string> inside of a |
| * std::optional<std::vector<std::optional<std::string>>> at index 'index' to size 'length' (or to |
| * std::nullopt when length is -1). |
| */ |
| static inline bool AParcel_nullableStdVectorStringElementAllocator(void* vectorData, size_t index, |
| int32_t length, char** buffer) { |
| std::optional<std::vector<std::optional<std::string>>>* vec = |
| static_cast<std::optional<std::vector<std::optional<std::string>>>*>(vectorData); |
| std::optional<std::string>& element = vec->value().at(index); |
| return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer); |
| } |
| |
| /** |
| * This gets the length and buffer of a std::optional<std::string> inside of a |
| * std::vector<std::string> at index index. If the string is null, then it returns null and a length |
| * of -1. |
| */ |
| static inline const char* AParcel_nullableStdVectorStringElementGetter(const void* vectorData, |
| size_t index, |
| int32_t* outLength) { |
| const std::optional<std::vector<std::optional<std::string>>>* vec = |
| static_cast<const std::optional<std::vector<std::optional<std::string>>>*>(vectorData); |
| const std::optional<std::string>& element = vec->value().at(index); |
| |
| if (!element) { |
| *outLength = -1; |
| return nullptr; |
| } |
| |
| *outLength = static_cast<int32_t>(element->size()); |
| return element->c_str(); |
| } |
| |
| /** |
| * This retrieves the underlying value in a std::array which may not be contiguous at index from a |
| * corresponding arrData. |
| */ |
| template <typename T, size_t N> |
| static inline T AParcel_stdArrayGetter(const void* arrData, size_t index) { |
| const std::array<T, N>* arr = static_cast<const std::array<T, N>*>(arrData); |
| return (*arr)[index]; |
| } |
| |
| /** |
| * This sets the underlying value in a corresponding arrData which may not be contiguous at |
| * index. |
| */ |
| template <typename T, size_t N> |
| static inline void AParcel_stdArraySetter(void* arrData, size_t index, T value) { |
| std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrData); |
| (*arr)[index] = value; |
| } |
| |
| /** |
| * This retrieves the underlying value in a std::array which may not be contiguous at index from a |
| * corresponding arrData. |
| */ |
| template <typename T, size_t N> |
| static inline T AParcel_nullableStdArrayGetter(const void* arrData, size_t index) { |
| const std::optional<std::array<T, N>>* arr = |
| static_cast<const std::optional<std::array<T, N>>*>(arrData); |
| return (*arr)[index]; |
| } |
| |
| /** |
| * This sets the underlying value in a corresponding arrData which may not be contiguous at |
| * index. |
| */ |
| template <typename T, size_t N> |
| static inline void AParcel_nullableStdArraySetter(void* arrData, size_t index, T value) { |
| std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrData); |
| (*arr)->at(index) = value; |
| } |
| |
| /** |
| * Allocates a std::string inside of std::array<std::string, N> at index 'index' to size 'length'. |
| */ |
| template <size_t N> |
| static inline bool AParcel_stdArrayStringElementAllocator(void* arrData, size_t index, |
| int32_t length, char** buffer) { |
| std::array<std::string, N>* arr = static_cast<std::array<std::string, N>*>(arrData); |
| std::string& element = arr->at(index); |
| return AParcel_stdStringAllocator(static_cast<void*>(&element), length, buffer); |
| } |
| |
| /** |
| * This gets the length and buffer of a std::string inside of a std::array<std::string, N> at index |
| * 'index'. |
| */ |
| template <size_t N> |
| static const char* AParcel_stdArrayStringElementGetter(const void* arrData, size_t index, |
| int32_t* outLength) { |
| const std::array<std::string, N>* arr = static_cast<const std::array<std::string, N>*>(arrData); |
| const std::string& element = arr->at(index); |
| |
| *outLength = static_cast<int32_t>(element.size()); |
| return element.c_str(); |
| } |
| |
| /** |
| * Allocates a std::string inside of std::array<std::optional<std::string>, N> at index 'index' to |
| * size 'length'. |
| */ |
| template <size_t N> |
| static inline bool AParcel_stdArrayNullableStringElementAllocator(void* arrData, size_t index, |
| int32_t length, char** buffer) { |
| std::array<std::optional<std::string>, N>* arr = |
| static_cast<std::array<std::optional<std::string>, N>*>(arrData); |
| std::optional<std::string>& element = arr->at(index); |
| return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer); |
| } |
| |
| /** |
| * This gets the length and buffer of a std::string inside of a |
| * std::array<std::optional<std::string>, N> at index 'index'. |
| */ |
| template <size_t N> |
| static const char* AParcel_stdArrayNullableStringElementGetter(const void* arrData, size_t index, |
| int32_t* outLength) { |
| const std::array<std::optional<std::string>, N>* arr = |
| static_cast<const std::array<std::optional<std::string>, N>*>(arrData); |
| const std::optional<std::string>& element = arr->at(index); |
| |
| if (!element) { |
| *outLength = -1; |
| return nullptr; |
| } |
| |
| *outLength = static_cast<int32_t>(element->size()); |
| return element->c_str(); |
| } |
| |
| /** |
| * Allocates a std::string inside of std::optional<std::array<std::optional<std::string>, N>> at |
| * index 'index' to size 'length'. |
| */ |
| template <size_t N> |
| static inline bool AParcel_nullableStdArrayStringElementAllocator(void* arrData, size_t index, |
| int32_t length, char** buffer) { |
| std::optional<std::array<std::optional<std::string>, N>>* arr = |
| static_cast<std::optional<std::array<std::optional<std::string>, N>>*>(arrData); |
| std::optional<std::string>& element = (*arr)->at(index); |
| return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer); |
| } |
| |
| /** |
| * Convenience API for writing a std::string. |
| */ |
| static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) { |
| return AParcel_writeString(parcel, str.c_str(), static_cast<int32_t>(str.size())); |
| } |
| |
| /** |
| * Convenience API for reading a std::string. |
| */ |
| static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) { |
| void* stringData = static_cast<void*>(str); |
| return AParcel_readString(parcel, stringData, AParcel_stdStringAllocator); |
| } |
| |
| /** |
| * Convenience API for writing a std::optional<std::string>. |
| */ |
| static inline binder_status_t AParcel_writeString(AParcel* parcel, |
| const std::optional<std::string>& str) { |
| if (!str) { |
| return AParcel_writeString(parcel, nullptr, -1); |
| } |
| |
| return AParcel_writeString(parcel, str->c_str(), static_cast<int32_t>(str->size())); |
| } |
| |
| /** |
| * Convenience API for reading a std::optional<std::string>. |
| */ |
| static inline binder_status_t AParcel_readString(const AParcel* parcel, |
| std::optional<std::string>* str) { |
| void* stringData = static_cast<void*>(str); |
| return AParcel_readString(parcel, stringData, AParcel_nullableStdStringAllocator); |
| } |
| |
| /** |
| * Convenience API for writing a std::vector<std::string> |
| */ |
| static inline binder_status_t AParcel_writeVector(AParcel* parcel, |
| const std::vector<std::string>& vec) { |
| const void* vectorData = static_cast<const void*>(&vec); |
| return AParcel_writeStringArray(parcel, vectorData, static_cast<int32_t>(vec.size()), |
| AParcel_stdVectorStringElementGetter); |
| } |
| |
| /** |
| * Convenience API for reading a std::vector<std::string> |
| */ |
| static inline binder_status_t AParcel_readVector(const AParcel* parcel, |
| std::vector<std::string>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readStringArray(parcel, vectorData, |
| AParcel_stdVectorExternalAllocator<std::string>, |
| AParcel_stdVectorStringElementAllocator); |
| } |
| |
| /** |
| * Convenience API for writing a std::optional<std::vector<std::optional<std::string>>> |
| */ |
| static inline binder_status_t AParcel_writeVector( |
| AParcel* parcel, const std::optional<std::vector<std::optional<std::string>>>& vec) { |
| const void* vectorData = static_cast<const void*>(&vec); |
| return AParcel_writeStringArray(parcel, vectorData, |
| (vec ? static_cast<int32_t>(vec->size()) : -1), |
| AParcel_nullableStdVectorStringElementGetter); |
| } |
| |
| /** |
| * Convenience API for reading a std::optional<std::vector<std::optional<std::string>>> |
| */ |
| static inline binder_status_t AParcel_readVector( |
| const AParcel* parcel, std::optional<std::vector<std::optional<std::string>>>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readStringArray( |
| parcel, vectorData, |
| AParcel_nullableStdVectorExternalAllocator<std::optional<std::string>>, |
| AParcel_nullableStdVectorStringElementAllocator); |
| } |
| |
| /** |
| * Convenience API for writing a non-null parcelable. |
| */ |
| template <typename P> |
| static inline binder_status_t AParcel_writeParcelable(AParcel* parcel, const P& p) { |
| if constexpr (is_interface_v<P>) { |
| // Legacy behavior: allow null |
| return first_template_type_t<P>::writeToParcel(parcel, p); |
| } else { |
| static_assert(is_parcelable_v<P>); |
| binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null |
| if (status != STATUS_OK) { |
| return status; |
| } |
| return p.writeToParcel(parcel); |
| } |
| } |
| |
| /** |
| * Convenience API for reading a non-null parcelable. |
| */ |
| template <typename P> |
| static inline binder_status_t AParcel_readParcelable(const AParcel* parcel, P* p) { |
| if constexpr (is_interface_v<P>) { |
| // Legacy behavior: allow null |
| return first_template_type_t<P>::readFromParcel(parcel, p); |
| } else { |
| static_assert(is_parcelable_v<P>); |
| int32_t null; |
| binder_status_t status = AParcel_readInt32(parcel, &null); |
| if (status != STATUS_OK) { |
| return status; |
| } |
| if (null == 0) { |
| return STATUS_UNEXPECTED_NULL; |
| } |
| return p->readFromParcel(parcel); |
| } |
| } |
| |
| /** |
| * Convenience API for writing a nullable parcelable. |
| */ |
| template <typename P> |
| static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel, const P& p) { |
| if constexpr (is_interface_v<P>) { |
| return first_template_type_t<P>::writeToParcel(parcel, p); |
| } else { |
| static_assert(is_nullable_parcelable_v<P>); |
| if (!p) { |
| return AParcel_writeInt32(parcel, 0); // null |
| } |
| binder_status_t status = AParcel_writeInt32(parcel, 1); // non-null |
| if (status != STATUS_OK) { |
| return status; |
| } |
| return p->writeToParcel(parcel); |
| } |
| } |
| |
| /** |
| * Convenience API for reading a nullable parcelable. |
| */ |
| template <typename P> |
| static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel, P* p) { |
| if constexpr (is_interface_v<P>) { |
| return first_template_type_t<P>::readFromParcel(parcel, p); |
| } else if constexpr (is_specialization_v<P, std::optional>) { |
| int32_t null; |
| binder_status_t status = AParcel_readInt32(parcel, &null); |
| if (status != STATUS_OK) { |
| return status; |
| } |
| if (null == 0) { |
| *p = std::nullopt; |
| return STATUS_OK; |
| } |
| p->emplace(first_template_type_t<P>()); |
| return (*p)->readFromParcel(parcel); |
| } else { |
| static_assert(is_specialization_v<P, std::unique_ptr>); |
| int32_t null; |
| binder_status_t status = AParcel_readInt32(parcel, &null); |
| if (status != STATUS_OK) { |
| return status; |
| } |
| if (null == 0) { |
| p->reset(); |
| return STATUS_OK; |
| } |
| *p = std::make_unique<first_template_type_t<P>>(); |
| return (*p)->readFromParcel(parcel); |
| } |
| } |
| |
| // Forward decls |
| template <typename T> |
| static inline binder_status_t AParcel_writeData(AParcel* parcel, const T& value); |
| template <typename T> |
| static inline binder_status_t AParcel_writeNullableData(AParcel* parcel, const T& value); |
| template <typename T> |
| static inline binder_status_t AParcel_readData(const AParcel* parcel, T* value); |
| template <typename T> |
| static inline binder_status_t AParcel_readNullableData(const AParcel* parcel, T* value); |
| |
| /** |
| * Reads an object of type T inside a std::array<T, N> at index 'index' from 'parcel'. |
| */ |
| template <typename T, size_t N> |
| binder_status_t AParcel_readStdArrayData(const AParcel* parcel, void* arrayData, size_t index) { |
| std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrayData); |
| return AParcel_readData(parcel, &arr->at(index)); |
| } |
| |
| /** |
| * Reads a nullable object of type T inside a std::array<T, N> at index 'index' from 'parcel'. |
| */ |
| template <typename T, size_t N> |
| binder_status_t AParcel_readStdArrayNullableData(const AParcel* parcel, void* arrayData, |
| size_t index) { |
| std::array<T, N>* arr = static_cast<std::array<T, N>*>(arrayData); |
| return AParcel_readNullableData(parcel, &arr->at(index)); |
| } |
| |
| /** |
| * Reads a nullable object of type T inside a std::array<T, N> at index 'index' from 'parcel'. |
| */ |
| template <typename T, size_t N> |
| binder_status_t AParcel_readNullableStdArrayNullableData(const AParcel* parcel, void* arrayData, |
| size_t index) { |
| std::optional<std::array<T, N>>* arr = static_cast<std::optional<std::array<T, N>>*>(arrayData); |
| return AParcel_readNullableData(parcel, &(*arr)->at(index)); |
| } |
| |
| /** |
| * Writes an object of type T inside a std::array<T, N> at index 'index' to 'parcel'. |
| */ |
| template <typename T, size_t N> |
| binder_status_t AParcel_writeStdArrayData(AParcel* parcel, const void* arrayData, size_t index) { |
| const std::array<T, N>* arr = static_cast<const std::array<T, N>*>(arrayData); |
| return AParcel_writeData(parcel, arr->at(index)); |
| } |
| |
| /** |
| * Writes a nullable object of type T inside a std::array<T, N> at index 'index' to 'parcel'. |
| */ |
| template <typename T, size_t N> |
| binder_status_t AParcel_writeStdArrayNullableData(AParcel* parcel, const void* arrayData, |
| size_t index) { |
| const std::array<T, N>* arr = static_cast<const std::array<T, N>*>(arrayData); |
| return AParcel_writeNullableData(parcel, arr->at(index)); |
| } |
| |
| /** |
| * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'. |
| */ |
| template <typename P> |
| binder_status_t AParcel_writeStdVectorParcelableElement(AParcel* parcel, const void* vectorData, |
| size_t index) { |
| const std::vector<P>* vector = static_cast<const std::vector<P>*>(vectorData); |
| return AParcel_writeParcelable(parcel, vector->at(index)); |
| } |
| |
| /** |
| * Reads a parcelable object of type P inside a std::vector<P> at index 'index' from 'parcel'. |
| */ |
| template <typename P> |
| binder_status_t AParcel_readStdVectorParcelableElement(const AParcel* parcel, void* vectorData, |
| size_t index) { |
| std::vector<P>* vector = static_cast<std::vector<P>*>(vectorData); |
| return AParcel_readParcelable(parcel, &vector->at(index)); |
| } |
| |
| /** |
| * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'. |
| */ |
| template <typename P> |
| binder_status_t AParcel_writeNullableStdVectorParcelableElement(AParcel* parcel, |
| const void* vectorData, |
| size_t index) { |
| const std::optional<std::vector<P>>* vector = |
| static_cast<const std::optional<std::vector<P>>*>(vectorData); |
| return AParcel_writeNullableParcelable(parcel, (*vector)->at(index)); |
| } |
| |
| /** |
| * Reads a parcelable object of type P inside a std::vector<P> at index 'index' from 'parcel'. |
| */ |
| template <typename P> |
| binder_status_t AParcel_readNullableStdVectorParcelableElement(const AParcel* parcel, |
| void* vectorData, size_t index) { |
| std::optional<std::vector<P>>* vector = static_cast<std::optional<std::vector<P>>*>(vectorData); |
| return AParcel_readNullableParcelable(parcel, &(*vector)->at(index)); |
| } |
| |
| /** |
| * Writes a ScopedFileDescriptor object inside a std::vector<ScopedFileDescriptor> at index 'index' |
| * to 'parcel'. |
| */ |
| template <> |
| inline binder_status_t AParcel_writeStdVectorParcelableElement<ScopedFileDescriptor>( |
| AParcel* parcel, const void* vectorData, size_t index) { |
| const std::vector<ScopedFileDescriptor>* vector = |
| static_cast<const std::vector<ScopedFileDescriptor>*>(vectorData); |
| return AParcel_writeRequiredParcelFileDescriptor(parcel, vector->at(index)); |
| } |
| |
| /** |
| * Reads a ScopedFileDescriptor object inside a std::vector<ScopedFileDescriptor> at index 'index' |
| * from 'parcel'. |
| */ |
| template <> |
| inline binder_status_t AParcel_readStdVectorParcelableElement<ScopedFileDescriptor>( |
| const AParcel* parcel, void* vectorData, size_t index) { |
| std::vector<ScopedFileDescriptor>* vector = |
| static_cast<std::vector<ScopedFileDescriptor>*>(vectorData); |
| return AParcel_readRequiredParcelFileDescriptor(parcel, &vector->at(index)); |
| } |
| |
| /** |
| * Writes a ScopedFileDescriptor object inside a std::optional<std::vector<ScopedFileDescriptor>> at |
| * index 'index' to 'parcel'. |
| */ |
| template <> |
| inline binder_status_t AParcel_writeNullableStdVectorParcelableElement<ScopedFileDescriptor>( |
| AParcel* parcel, const void* vectorData, size_t index) { |
| const std::optional<std::vector<ScopedFileDescriptor>>* vector = |
| static_cast<const std::optional<std::vector<ScopedFileDescriptor>>*>(vectorData); |
| return AParcel_writeNullableParcelFileDescriptor(parcel, (*vector)->at(index)); |
| } |
| |
| /** |
| * Reads a ScopedFileDescriptor object inside a std::optional<std::vector<ScopedFileDescriptor>> at |
| * index 'index' from 'parcel'. |
| */ |
| template <> |
| inline binder_status_t AParcel_readNullableStdVectorParcelableElement<ScopedFileDescriptor>( |
| const AParcel* parcel, void* vectorData, size_t index) { |
| std::optional<std::vector<ScopedFileDescriptor>>* vector = |
| static_cast<std::optional<std::vector<ScopedFileDescriptor>>*>(vectorData); |
| return AParcel_readNullableParcelFileDescriptor(parcel, &(*vector)->at(index)); |
| } |
| |
| /** |
| * Writes an SpAIBinder object inside a std::vector<SpAIBinder> at index 'index' |
| * to 'parcel'. |
| */ |
| template <> |
| inline binder_status_t AParcel_writeStdVectorParcelableElement<SpAIBinder>(AParcel* parcel, |
| const void* vectorData, |
| size_t index) { |
| const std::vector<SpAIBinder>* vector = static_cast<const std::vector<SpAIBinder>*>(vectorData); |
| return AParcel_writeRequiredStrongBinder(parcel, vector->at(index)); |
| } |
| |
| /** |
| * Reads an SpAIBinder object inside a std::vector<SpAIBinder> at index 'index' |
| * from 'parcel'. |
| */ |
| template <> |
| inline binder_status_t AParcel_readStdVectorParcelableElement<SpAIBinder>(const AParcel* parcel, |
| void* vectorData, |
| size_t index) { |
| std::vector<SpAIBinder>* vector = static_cast<std::vector<SpAIBinder>*>(vectorData); |
| return AParcel_readRequiredStrongBinder(parcel, &vector->at(index)); |
| } |
| |
| /** |
| * Writes an SpAIBinder object inside a std::optional<std::vector<SpAIBinder>> at index 'index' |
| * to 'parcel'. |
| */ |
| template <> |
| inline binder_status_t AParcel_writeNullableStdVectorParcelableElement<SpAIBinder>( |
| AParcel* parcel, const void* vectorData, size_t index) { |
| const std::optional<std::vector<SpAIBinder>>* vector = |
| static_cast<const std::optional<std::vector<SpAIBinder>>*>(vectorData); |
| return AParcel_writeNullableStrongBinder(parcel, (*vector)->at(index)); |
| } |
| |
| /** |
| * Reads an SpAIBinder object inside a std::optional<std::vector<SpAIBinder>> at index 'index' |
| * from 'parcel'. |
| */ |
| template <> |
| inline binder_status_t AParcel_readNullableStdVectorParcelableElement<SpAIBinder>( |
| const AParcel* parcel, void* vectorData, size_t index) { |
| std::optional<std::vector<SpAIBinder>>* vector = |
| static_cast<std::optional<std::vector<SpAIBinder>>*>(vectorData); |
| return AParcel_readNullableStrongBinder(parcel, &(*vector)->at(index)); |
| } |
| |
| /** |
| * Convenience API for writing a std::vector<P> |
| */ |
| template <typename P> |
| static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<P>& vec) { |
| if constexpr (std::is_enum_v<P>) { |
| if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) { |
| return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(vec.data()), |
| static_cast<int32_t>(vec.size())); |
| } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) { |
| return AParcel_writeInt32Array(parcel, reinterpret_cast<const int32_t*>(vec.data()), |
| static_cast<int32_t>(vec.size())); |
| } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) { |
| return AParcel_writeInt64Array(parcel, reinterpret_cast<const int64_t*>(vec.data()), |
| static_cast<int32_t>(vec.size())); |
| } else { |
| static_assert(dependent_false_v<P>, "unrecognized type"); |
| } |
| } else { |
| static_assert(!std::is_same_v<P, std::string>, "specialization should be used"); |
| const void* vectorData = static_cast<const void*>(&vec); |
| return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec.size()), |
| AParcel_writeStdVectorParcelableElement<P>); |
| } |
| } |
| |
| /** |
| * Convenience API for reading a std::vector<P> |
| */ |
| template <typename P> |
| static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<P>* vec) { |
| if constexpr (std::is_enum_v<P>) { |
| void* vectorData = static_cast<void*>(vec); |
| if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) { |
| return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>); |
| } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) { |
| return AParcel_readInt32Array(parcel, vectorData, AParcel_stdVectorAllocator<int32_t>); |
| } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) { |
| return AParcel_readInt64Array(parcel, vectorData, AParcel_stdVectorAllocator<int64_t>); |
| } else { |
| static_assert(dependent_false_v<P>, "unrecognized type"); |
| } |
| } else { |
| static_assert(!std::is_same_v<P, std::string>, "specialization should be used"); |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readParcelableArray(parcel, vectorData, |
| AParcel_stdVectorExternalAllocator<P>, |
| AParcel_readStdVectorParcelableElement<P>); |
| } |
| } |
| |
| /** |
| * Convenience API for writing a std::optional<std::vector<P>> |
| */ |
| template <typename P> |
| static inline binder_status_t AParcel_writeVector(AParcel* parcel, |
| const std::optional<std::vector<P>>& vec) { |
| if constexpr (std::is_enum_v<P>) { |
| if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) { |
| return AParcel_writeByteArray( |
| parcel, vec ? reinterpret_cast<const int8_t*>(vec->data()) : nullptr, |
| vec ? static_cast<int32_t>(vec->size()) : -1); |
| } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) { |
| return AParcel_writeInt32Array( |
| parcel, vec ? reinterpret_cast<const int32_t*>(vec->data()) : nullptr, |
| vec ? static_cast<int32_t>(vec->size()) : -1); |
| } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) { |
| return AParcel_writeInt64Array( |
| parcel, vec ? reinterpret_cast<const int64_t*>(vec->data()) : nullptr, |
| vec ? static_cast<int32_t>(vec->size()) : -1); |
| } else { |
| static_assert(dependent_false_v<P>, "unrecognized type"); |
| } |
| } else { |
| static_assert(!std::is_same_v<P, std::optional<std::string>>, |
| "specialization should be used"); |
| if (!vec) return AParcel_writeInt32(parcel, -1); |
| const void* vectorData = static_cast<const void*>(&vec); |
| return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec->size()), |
| AParcel_writeNullableStdVectorParcelableElement<P>); |
| } |
| } |
| |
| /** |
| * Convenience API for reading a std::optional<std::vector<P>> |
| */ |
| template <typename P> |
| static inline binder_status_t AParcel_readVector(const AParcel* parcel, |
| std::optional<std::vector<P>>* vec) { |
| if constexpr (std::is_enum_v<P>) { |
| void* vectorData = static_cast<void*>(vec); |
| if constexpr (std::is_same_v<std::underlying_type_t<P>, int8_t>) { |
| return AParcel_readByteArray(parcel, vectorData, |
| AParcel_nullableStdVectorAllocator<int8_t>); |
| } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int32_t>) { |
| return AParcel_readInt32Array(parcel, vectorData, |
| AParcel_nullableStdVectorAllocator<int32_t>); |
| } else if constexpr (std::is_same_v<std::underlying_type_t<P>, int64_t>) { |
| return AParcel_readInt64Array(parcel, vectorData, |
| AParcel_nullableStdVectorAllocator<int64_t>); |
| } else { |
| static_assert(dependent_false_v<P>, "unrecognized type"); |
| } |
| } else { |
| static_assert(!std::is_same_v<P, std::optional<std::string>>, |
| "specialization should be used"); |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readParcelableArray(parcel, vectorData, |
| AParcel_nullableStdVectorExternalAllocator<P>, |
| AParcel_readNullableStdVectorParcelableElement<P>); |
| } |
| } |
| |
| // @START |
| /** |
| * Writes a vector of int32_t to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) { |
| return AParcel_writeInt32Array(parcel, vec.data(), static_cast<int32_t>(vec.size())); |
| } |
| |
| /** |
| * Writes an optional vector of int32_t to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, |
| const std::optional<std::vector<int32_t>>& vec) { |
| if (!vec) return AParcel_writeInt32Array(parcel, nullptr, -1); |
| return AParcel_writeVector(parcel, *vec); |
| } |
| |
| /** |
| * Reads a vector of int32_t from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int32_t>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readInt32Array(parcel, vectorData, AParcel_stdVectorAllocator<int32_t>); |
| } |
| |
| /** |
| * Reads an optional vector of int32_t from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, |
| std::optional<std::vector<int32_t>>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readInt32Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int32_t>); |
| } |
| |
| /** |
| * Writes a vector of uint32_t to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) { |
| return AParcel_writeUint32Array(parcel, vec.data(), static_cast<int32_t>(vec.size())); |
| } |
| |
| /** |
| * Writes an optional vector of uint32_t to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, |
| const std::optional<std::vector<uint32_t>>& vec) { |
| if (!vec) return AParcel_writeUint32Array(parcel, nullptr, -1); |
| return AParcel_writeVector(parcel, *vec); |
| } |
| |
| /** |
| * Reads a vector of uint32_t from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint32_t>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readUint32Array(parcel, vectorData, AParcel_stdVectorAllocator<uint32_t>); |
| } |
| |
| /** |
| * Reads an optional vector of uint32_t from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, |
| std::optional<std::vector<uint32_t>>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readUint32Array(parcel, vectorData, |
| AParcel_nullableStdVectorAllocator<uint32_t>); |
| } |
| |
| /** |
| * Writes a vector of int64_t to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) { |
| return AParcel_writeInt64Array(parcel, vec.data(), static_cast<int32_t>(vec.size())); |
| } |
| |
| /** |
| * Writes an optional vector of int64_t to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, |
| const std::optional<std::vector<int64_t>>& vec) { |
| if (!vec) return AParcel_writeInt64Array(parcel, nullptr, -1); |
| return AParcel_writeVector(parcel, *vec); |
| } |
| |
| /** |
| * Reads a vector of int64_t from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int64_t>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readInt64Array(parcel, vectorData, AParcel_stdVectorAllocator<int64_t>); |
| } |
| |
| /** |
| * Reads an optional vector of int64_t from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, |
| std::optional<std::vector<int64_t>>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readInt64Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int64_t>); |
| } |
| |
| /** |
| * Writes a vector of uint64_t to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) { |
| return AParcel_writeUint64Array(parcel, vec.data(), static_cast<int32_t>(vec.size())); |
| } |
| |
| /** |
| * Writes an optional vector of uint64_t to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, |
| const std::optional<std::vector<uint64_t>>& vec) { |
| if (!vec) return AParcel_writeUint64Array(parcel, nullptr, -1); |
| return AParcel_writeVector(parcel, *vec); |
| } |
| |
| /** |
| * Reads a vector of uint64_t from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint64_t>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readUint64Array(parcel, vectorData, AParcel_stdVectorAllocator<uint64_t>); |
| } |
| |
| /** |
| * Reads an optional vector of uint64_t from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, |
| std::optional<std::vector<uint64_t>>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readUint64Array(parcel, vectorData, |
| AParcel_nullableStdVectorAllocator<uint64_t>); |
| } |
| |
| /** |
| * Writes a vector of float to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) { |
| return AParcel_writeFloatArray(parcel, vec.data(), static_cast<int32_t>(vec.size())); |
| } |
| |
| /** |
| * Writes an optional vector of float to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, |
| const std::optional<std::vector<float>>& vec) { |
| if (!vec) return AParcel_writeFloatArray(parcel, nullptr, -1); |
| return AParcel_writeVector(parcel, *vec); |
| } |
| |
| /** |
| * Reads a vector of float from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<float>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readFloatArray(parcel, vectorData, AParcel_stdVectorAllocator<float>); |
| } |
| |
| /** |
| * Reads an optional vector of float from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, |
| std::optional<std::vector<float>>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readFloatArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<float>); |
| } |
| |
| /** |
| * Writes a vector of double to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) { |
| return AParcel_writeDoubleArray(parcel, vec.data(), static_cast<int32_t>(vec.size())); |
| } |
| |
| /** |
| * Writes an optional vector of double to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, |
| const std::optional<std::vector<double>>& vec) { |
| if (!vec) return AParcel_writeDoubleArray(parcel, nullptr, -1); |
| return AParcel_writeVector(parcel, *vec); |
| } |
| |
| /** |
| * Reads a vector of double from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<double>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readDoubleArray(parcel, vectorData, AParcel_stdVectorAllocator<double>); |
| } |
| |
| /** |
| * Reads an optional vector of double from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, |
| std::optional<std::vector<double>>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readDoubleArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<double>); |
| } |
| |
| /** |
| * Writes a vector of bool to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) { |
| return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec), |
| static_cast<int32_t>(vec.size()), AParcel_stdVectorGetter<bool>); |
| } |
| |
| /** |
| * Writes an optional vector of bool to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, |
| const std::optional<std::vector<bool>>& vec) { |
| if (!vec) return AParcel_writeBoolArray(parcel, nullptr, -1, AParcel_stdVectorGetter<bool>); |
| return AParcel_writeVector(parcel, *vec); |
| } |
| |
| /** |
| * Reads a vector of bool from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<bool>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readBoolArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<bool>, |
| AParcel_stdVectorSetter<bool>); |
| } |
| |
| /** |
| * Reads an optional vector of bool from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, |
| std::optional<std::vector<bool>>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readBoolArray(parcel, vectorData, |
| AParcel_nullableStdVectorExternalAllocator<bool>, |
| AParcel_nullableStdVectorSetter<bool>); |
| } |
| |
| /** |
| * Writes a vector of char16_t to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) { |
| return AParcel_writeCharArray(parcel, vec.data(), static_cast<int32_t>(vec.size())); |
| } |
| |
| /** |
| * Writes an optional vector of char16_t to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, |
| const std::optional<std::vector<char16_t>>& vec) { |
| if (!vec) return AParcel_writeCharArray(parcel, nullptr, -1); |
| return AParcel_writeVector(parcel, *vec); |
| } |
| |
| /** |
| * Reads a vector of char16_t from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<char16_t>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readCharArray(parcel, vectorData, AParcel_stdVectorAllocator<char16_t>); |
| } |
| |
| /** |
| * Reads an optional vector of char16_t from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, |
| std::optional<std::vector<char16_t>>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readCharArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<char16_t>); |
| } |
| |
| /** |
| * Writes a vector of uint8_t to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint8_t>& vec) { |
| return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(vec.data()), |
| static_cast<int32_t>(vec.size())); |
| } |
| |
| /** |
| * Writes an optional vector of uint8_t to the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_writeVector(AParcel* parcel, |
| const std::optional<std::vector<uint8_t>>& vec) { |
| if (!vec) return AParcel_writeByteArray(parcel, nullptr, -1); |
| return AParcel_writeVector(parcel, *vec); |
| } |
| |
| /** |
| * Reads a vector of uint8_t from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint8_t>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>); |
| } |
| |
| /** |
| * Reads an optional vector of uint8_t from the next location in a non-null parcel. |
| */ |
| inline binder_status_t AParcel_readVector(const AParcel* parcel, |
| std::optional<std::vector<uint8_t>>* vec) { |
| void* vectorData = static_cast<void*>(vec); |
| return AParcel_readByteArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<int8_t>); |
| } |
| |
| // @END |
| |
| /** |
| * Convenience API for writing the size of a vector. |
| */ |
| template <typename T> |
| static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, const std::vector<T>& vec) { |
| if (vec.size() > INT32_MAX) { |
| return STATUS_BAD_VALUE; |
| } |
| |
| return AParcel_writeInt32(parcel, static_cast<int32_t>(vec.size())); |
| } |
| |
| /** |
| * Convenience API for writing the size of a vector. |
| */ |
| template <typename T> |
| static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, |
| const std::optional<std::vector<T>>& vec) { |
| if (!vec) { |
| return AParcel_writeInt32(parcel, -1); |
| } |
| |
| if (vec->size() > INT32_MAX) { |
| return STATUS_BAD_VALUE; |
| } |
| |
| return AParcel_writeInt32(parcel, static_cast<int32_t>(vec->size())); |
| } |
| |
| /** |
| * Convenience API for resizing a vector. |
| */ |
| template <typename T> |
| static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, std::vector<T>* vec) { |
| int32_t size; |
| binder_status_t err = AParcel_readInt32(parcel, &size); |
| |
| if (err != STATUS_OK) return err; |
| if (size < 0) return STATUS_UNEXPECTED_NULL; |
| |
| // TODO(b/188215728): delegate to libbinder_ndk |
| if (size > 1000000) return STATUS_NO_MEMORY; |
| |
| vec->resize(static_cast<size_t>(size)); |
| return STATUS_OK; |
| } |
| |
| /** |
| * Convenience API for resizing a vector. |
| */ |
| template <typename T> |
| static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, |
| std::optional<std::vector<T>>* vec) { |
| int32_t size; |
| binder_status_t err = AParcel_readInt32(parcel, &size); |
| |
| if (err != STATUS_OK) return err; |
| if (size < -1) return STATUS_UNEXPECTED_NULL; |
| |
| if (size == -1) { |
| *vec = std::nullopt; |
| return STATUS_OK; |
| } |
| |
| // TODO(b/188215728): delegate to libbinder_ndk |
| if (size > 1000000) return STATUS_NO_MEMORY; |
| |
| *vec = std::optional<std::vector<T>>(std::vector<T>{}); |
| (*vec)->resize(static_cast<size_t>(size)); |
| return STATUS_OK; |
| } |
| |
| /** |
| * Writes a fixed-size array of T. |
| */ |
| template <typename T, size_t N> |
| static inline binder_status_t AParcel_writeFixedArray(AParcel* parcel, |
| const std::array<T, N>& arr) { |
| if constexpr (std::is_same_v<T, bool>) { |
| const void* arrayData = static_cast<const void*>(&arr); |
| return AParcel_writeBoolArray(parcel, arrayData, static_cast<int32_t>(N), |
| &AParcel_stdArrayGetter<T, N>); |
| } else if constexpr (std::is_same_v<T, uint8_t>) { |
| return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(arr.data()), |
| static_cast<int32_t>(arr.size())); |
| } else if constexpr (std::is_same_v<T, char16_t>) { |
| return AParcel_writeCharArray(parcel, arr.data(), static_cast<int32_t>(arr.size())); |
| } else if constexpr (std::is_same_v<T, int32_t>) { |
| return AParcel_writeInt32Array(parcel, arr.data(), static_cast<int32_t>(arr.size())); |
| } else if constexpr (std::is_same_v<T, int64_t>) { |
| return AParcel_writeInt64Array(parcel, arr.data(), static_cast<int32_t>(arr.size())); |
| } else if constexpr (std::is_same_v<T, float>) { |
| return AParcel_writeFloatArray(parcel, arr.data(), static_cast<int32_t>(arr.size())); |
| } else if constexpr (std::is_same_v<T, double>) { |
| return AParcel_writeDoubleArray(parcel, arr.data(), static_cast<int32_t>(arr.size())); |
| } else if constexpr (std::is_same_v<T, std::string>) { |
| const void* arrayData = static_cast<const void*>(&arr); |
| return AParcel_writeStringArray(parcel, arrayData, static_cast<int32_t>(N), |
| &AParcel_stdArrayStringElementGetter<N>); |
| } else { |
| const void* arrayData = static_cast<const void*>(&arr); |
| return AParcel_writeParcelableArray(parcel, arrayData, static_cast<int32_t>(N), |
| &AParcel_writeStdArrayData<T, N>); |
| } |
| } |
| |
| /** |
| * Writes a fixed-size array of T. |
| */ |
| template <typename T, size_t N> |
| static inline binder_status_t AParcel_writeFixedArrayWithNullableData(AParcel* parcel, |
| const std::array<T, N>& arr) { |
| if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, uint8_t> || |
| std::is_same_v<T, char16_t> || std::is_same_v<T, int32_t> || |
| std::is_same_v<T, int64_t> || std::is_same_v<T, float> || |
| std::is_same_v<T, double> || std::is_same_v<T, std::string>) { |
| return AParcel_writeFixedArray(parcel, arr); |
| } else if constexpr (std::is_same_v<T, std::optional<std::string>>) { |
| const void* arrayData = static_cast<const void*>(&arr); |
| return AParcel_writeStringArray(parcel, arrayData, static_cast<int32_t>(N), |
| &AParcel_stdArrayNullableStringElementGetter<N>); |
| } else { |
| const void* arrayData = static_cast<const void*>(&arr); |
| return AParcel_writeParcelableArray(parcel, arrayData, static_cast<int32_t>(N), |
| &AParcel_writeStdArrayNullableData<T, N>); |
| } |
| } |
| |
| /** |
| * Writes a fixed-size array of T. |
| */ |
| template <typename T, size_t N> |
| static inline binder_status_t AParcel_writeNullableFixedArrayWithNullableData( |
| AParcel* parcel, const std::optional<std::array<T, N>>& arr) { |
| if (!arr) return AParcel_writeInt32(parcel, -1); |
| return AParcel_writeFixedArrayWithNullableData(parcel, arr.value()); |
| } |
| |
| /** |
| * Reads a fixed-size array of T. |
| */ |
| template <typename T, size_t N> |
| static inline binder_status_t AParcel_readFixedArray(const AParcel* parcel, std::array<T, N>* arr) { |
| void* arrayData = static_cast<void*>(arr); |
| if constexpr (std::is_same_v<T, bool>) { |
| return AParcel_readBoolArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>, |
| &AParcel_stdArraySetter<T, N>); |
| } else if constexpr (std::is_same_v<T, uint8_t>) { |
| return AParcel_readByteArray(parcel, arrayData, &AParcel_stdArrayAllocator<int8_t, N>); |
| } else if constexpr (std::is_same_v<T, char16_t>) { |
| return AParcel_readCharArray(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>); |
| } else if constexpr (std::is_same_v<T, int32_t>) { |
| return AParcel_readInt32Array(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>); |
| } else if constexpr (std::is_same_v<T, int64_t>) { |
| return AParcel_readInt64Array(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>); |
| } else if constexpr (std::is_same_v<T, float>) { |
| return AParcel_readFloatArray(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>); |
| } else if constexpr (std::is_same_v<T, double>) { |
| return AParcel_readDoubleArray(parcel, arrayData, &AParcel_stdArrayAllocator<T, N>); |
| } else if constexpr (std::is_same_v<T, std::string>) { |
| return AParcel_readStringArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>, |
| &AParcel_stdArrayStringElementAllocator<N>); |
| } else { |
| return AParcel_readParcelableArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>, |
| &AParcel_readStdArrayData<T, N>); |
| } |
| } |
| |
| /** |
| * Reads a fixed-size array of T. |
| */ |
| template <typename T, size_t N> |
| static inline binder_status_t AParcel_readFixedArrayWithNullableData(const AParcel* parcel, |
| std::array<T, N>* arr) { |
| void* arrayData = static_cast<void*>(arr); |
| if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, uint8_t> || |
| std::is_same_v<T, char16_t> || std::is_same_v<T, int32_t> || |
| std::is_same_v<T, int64_t> || std::is_same_v<T, float> || |
| std::is_same_v<T, double> || std::is_same_v<T, std::string>) { |
| return AParcel_readFixedArray(parcel, arr); |
| } else if constexpr (std::is_same_v<T, std::optional<std::string>>) { |
| return AParcel_readStringArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>, |
| &AParcel_stdArrayNullableStringElementAllocator<N>); |
| } else { |
| return AParcel_readParcelableArray(parcel, arrayData, &AParcel_stdArrayExternalAllocator<N>, |
| &AParcel_readStdArrayNullableData<T, N>); |
| } |
| } |
| |
| /** |
| * Reads a fixed-size array of T. |
| */ |
| template <typename T, size_t N> |
| static inline binder_status_t AParcel_readNullableFixedArrayWithNullableData( |
| const AParcel* parcel, std::optional<std::array<T, N>>* arr) { |
| void* arrayData = static_cast<void*>(arr); |
| if constexpr (std::is_same_v<T, bool>) { |
| return AParcel_readBoolArray(parcel, arrayData, |
| &AParcel_nullableStdArrayExternalAllocator<T, N>, |
| &AParcel_nullableStdArraySetter<T, N>); |
| } else if constexpr (std::is_same_v<T, uint8_t>) { |
| return AParcel_readByteArray(parcel, arrayData, |
| &AParcel_nullableStdArrayAllocator<int8_t, N>); |
| } else if constexpr (std::is_same_v<T, char16_t>) { |
| return AParcel_readCharArray(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>); |
| } else if constexpr (std::is_same_v<T, int32_t>) { |
| return AParcel_readInt32Array(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>); |
| } else if constexpr (std::is_same_v<T, int64_t>) { |
| return AParcel_readInt64Array(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>); |
| } else if constexpr (std::is_same_v<T, float>) { |
| return AParcel_readFloatArray(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>); |
| } else if constexpr (std::is_same_v<T, double>) { |
| return AParcel_readDoubleArray(parcel, arrayData, &AParcel_nullableStdArrayAllocator<T, N>); |
| } else if constexpr (std::is_same_v<T, std::string>) { |
| return AParcel_readStringArray(parcel, arrayData, |
| &AParcel_nullableStdArrayExternalAllocator<N>, |
| &AParcel_nullableStdArrayStringElementAllocator<N>); |
| } else { |
| return AParcel_readParcelableArray(parcel, arrayData, |
| &AParcel_nullableStdArrayExternalAllocator<T, N>, |
| &AParcel_readStdArrayNullableData<T, N>); |
| } |
| } |
| |
| /** |
| * Convenience API for writing a value of any type. |
| */ |
| template <typename T> |
| static inline binder_status_t AParcel_writeData(AParcel* parcel, const T& value) { |
| if constexpr (is_specialization_v<T, std::vector>) { |
| return AParcel_writeVector(parcel, value); |
| } else if constexpr (is_fixed_array_v<T>) { |
| return AParcel_writeFixedArray(parcel, value); |
| } else if constexpr (std::is_same_v<std::string, T>) { |
| return AParcel_writeString(parcel, value); |
| } else if constexpr (std::is_same_v<bool, T>) { |
| return AParcel_writeBool(parcel, value); |
| } else if constexpr (std::is_same_v<int8_t, T> || std::is_same_v<uint8_t, T>) { |
| return AParcel_writeByte(parcel, value); |
| } else if constexpr (std::is_same_v<char16_t, T>) { |
| return AParcel_writeChar(parcel, value); |
| } else if constexpr (std::is_same_v<int32_t, T>) { |
| return AParcel_writeInt32(parcel, value); |
| } else if constexpr (std::is_same_v<int64_t, T>) { |
| return AParcel_writeInt64(parcel, value); |
| } else if constexpr (std::is_same_v<float, T>) { |
| return AParcel_writeFloat(parcel, value); |
| } else if constexpr (std::is_same_v<double, T>) { |
| return AParcel_writeDouble(parcel, value); |
| } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) { |
| return AParcel_writeRequiredParcelFileDescriptor(parcel, value); |
| } else if constexpr (std::is_same_v<SpAIBinder, T>) { |
| return AParcel_writeRequiredStrongBinder(parcel, value); |
| } else if constexpr (std::is_enum_v<T>) { |
| return AParcel_writeData(parcel, static_cast<std::underlying_type_t<T>>(value)); |
| } else if constexpr (is_interface_v<T>) { |
| return AParcel_writeParcelable(parcel, value); |
| } else if constexpr (is_parcelable_v<T>) { |
| return AParcel_writeParcelable(parcel, value); |
| } else { |
| static_assert(dependent_false_v<T>, "unrecognized type"); |
| return STATUS_OK; |
| } |
| } |
| |
| /** |
| * Convenience API for writing a nullable value of any type. |
| */ |
| template <typename T> |
| static inline binder_status_t AParcel_writeNullableData(AParcel* parcel, const T& value) { |
| if constexpr (is_specialization_v<T, std::optional> && |
| is_specialization_v<first_template_type_t<T>, std::vector>) { |
| return AParcel_writeVector(parcel, value); |
| } else if constexpr (is_specialization_v<T, std::optional> && |
| is_fixed_array_v<first_template_type_t<T>>) { |
| return AParcel_writeNullableFixedArrayWithNullableData(parcel, value); |
| } else if constexpr (is_fixed_array_v<T>) { // happens with a nullable multi-dimensional array. |
| return AParcel_writeFixedArrayWithNullableData(parcel, value); |
| } else if constexpr (is_specialization_v<T, std::optional> && |
| std::is_same_v<first_template_type_t<T>, std::string>) { |
| return AParcel_writeString(parcel, value); |
| } else if constexpr (is_nullable_parcelable_v<T> || is_interface_v<T>) { |
| return AParcel_writeNullableParcelable(parcel, value); |
| } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) { |
| return AParcel_writeNullableParcelFileDescriptor(parcel, value); |
| } else if constexpr (std::is_same_v<SpAIBinder, T>) { |
| return AParcel_writeNullableStrongBinder(parcel, value); |
| } else { |
| return AParcel_writeData(parcel, value); |
| } |
| } |
| |
| /** |
| * Convenience API for reading a value of any type. |
| */ |
| template <typename T> |
| static inline binder_status_t AParcel_readData(const AParcel* parcel, T* value) { |
| if constexpr (is_specialization_v<T, std::vector>) { |
| return AParcel_readVector(parcel, value); |
| } else if constexpr (is_fixed_array_v<T>) { |
| return AParcel_readFixedArray(parcel, value); |
| } else if constexpr (std::is_same_v<std::string, T>) { |
| return AParcel_readString(parcel, value); |
| } else if constexpr (std::is_same_v<bool, T>) { |
| return AParcel_readBool(parcel, value); |
| } else if constexpr (std::is_same_v<int8_t, T> || std::is_same_v<uint8_t, T>) { |
| return AParcel_readByte(parcel, value); |
| } else if constexpr (std::is_same_v<char16_t, T>) { |
| return AParcel_readChar(parcel, value); |
| } else if constexpr (std::is_same_v<int32_t, T>) { |
| return AParcel_readInt32(parcel, value); |
| } else if constexpr (std::is_same_v<int64_t, T>) { |
| return AParcel_readInt64(parcel, value); |
| } else if constexpr (std::is_same_v<float, T>) { |
| return AParcel_readFloat(parcel, value); |
| } else if constexpr (std::is_same_v<double, T>) { |
| return AParcel_readDouble(parcel, value); |
| } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) { |
| return AParcel_readRequiredParcelFileDescriptor(parcel, value); |
| } else if constexpr (std::is_same_v<SpAIBinder, T>) { |
| return AParcel_readRequiredStrongBinder(parcel, value); |
| } else if constexpr (std::is_enum_v<T>) { |
| return AParcel_readData(parcel, reinterpret_cast<std::underlying_type_t<T>*>(value)); |
| } else if constexpr (is_interface_v<T>) { |
| return AParcel_readParcelable(parcel, value); |
| } else if constexpr (is_parcelable_v<T>) { |
| return AParcel_readParcelable(parcel, value); |
| } else { |
| static_assert(dependent_false_v<T>, "unrecognized type"); |
| return STATUS_OK; |
| } |
| } |
| |
| /** |
| * Convenience API for reading a nullable value of any type. |
| */ |
| template <typename T> |
| static inline binder_status_t AParcel_readNullableData(const AParcel* parcel, T* value) { |
| if constexpr (is_specialization_v<T, std::optional> && |
| is_specialization_v<first_template_type_t<T>, std::vector>) { |
| return AParcel_readVector(parcel, value); |
| } else if constexpr (is_specialization_v<T, std::optional> && |
| is_fixed_array_v<first_template_type_t<T>>) { |
| return AParcel_readNullableFixedArrayWithNullableData(parcel, value); |
| } else if constexpr (is_fixed_array_v<T>) { // happens with a nullable multi-dimensional array. |
| return AParcel_readFixedArrayWithNullableData(parcel, value); |
| } else if constexpr (is_specialization_v<T, std::optional> && |
| std::is_same_v<first_template_type_t<T>, std::string>) { |
| return AParcel_readString(parcel, value); |
| } else if constexpr (is_nullable_parcelable_v<T> || is_interface_v<T>) { |
| return AParcel_readNullableParcelable(parcel, value); |
| } else if constexpr (std::is_same_v<ScopedFileDescriptor, T>) { |
| return AParcel_readNullableParcelFileDescriptor(parcel, value); |
| } else if constexpr (std::is_same_v<SpAIBinder, T>) { |
| return AParcel_readNullableStrongBinder(parcel, value); |
| } else { |
| return AParcel_readData(parcel, value); |
| } |
| } |
| |
| } // namespace ndk |
| |
| /** @} */ |