| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef LIB_FIDL_CPP_CLONE_H_ |
| #define LIB_FIDL_CPP_CLONE_H_ |
| |
| #include <zircon/assert.h> |
| |
| #include <array> |
| #include <memory> |
| |
| #include "lib/fidl/cpp/string.h" |
| #include "lib/fidl/cpp/traits.h" |
| #include "lib/fidl/cpp/vector.h" |
| #include "types.h" |
| |
| namespace fidl { |
| |
| #ifdef __Fuchsia__ |
| namespace internal { |
| |
| template <typename T> |
| inline typename std::enable_if<zx::object_traits<T>::supports_duplication, zx_status_t>::type |
| CloneKernelObject(const zx::object<T>& object, zx::object<T>* result) { |
| return object.duplicate(ZX_RIGHT_SAME_RIGHTS, result); |
| } |
| |
| template <typename T> |
| inline typename std::enable_if<!zx::object_traits<T>::supports_duplication, zx_status_t>::type |
| CloneKernelObject(const zx::object<T>& object, zx::object<T>* result) { |
| return ZX_ERR_ACCESS_DENIED; |
| } |
| |
| } // namespace internal |
| #endif // __Fuchsia__ |
| |
| // Deep copies the contents of |value| into |result|. |
| // This operation also attempts to duplicate any handles the value contains. |
| // |
| // Returns an error if the value could not be cloned, perhaps because a |
| // handle was not duplicable. |
| // |
| // There are many overloads of this function with the following signature: |
| // zx_status_t Clone(const T& value, T* result); |
| template <typename T> |
| inline typename std::enable_if<IsPrimitive<T>::value, zx_status_t>::type Clone(const T& value, |
| T* result) { |
| *result = value; |
| return ZX_OK; |
| } |
| |
| // Forward-declare some templates: |
| template <typename T, size_t N> |
| inline typename std::enable_if<IsPrimitive<T>::value || IsStdString<T>::value, zx_status_t>::type |
| Clone(const std::array<T, N>& value, std::array<T, N>* result); |
| template <typename T, size_t N> |
| inline typename std::enable_if<!IsPrimitive<T>::value && !IsStdString<T>::value, zx_status_t>::type |
| Clone(const std::array<T, N>& value, std::array<T, N>* result); |
| |
| template <typename T> |
| inline |
| #ifdef __Fuchsia__ |
| typename std::enable_if<!IsPrimitive<T>::value && !std::is_base_of<zx::object_base, T>::value && |
| !IsStdVector<T>::value && !IsStdArray<T>::value, |
| zx_status_t>::type |
| #else // __Fuchsia__ |
| typename std::enable_if<!IsPrimitive<T>::value && !IsStdVector<T>::value && |
| !IsStdArray<T>::value, |
| zx_status_t>::type |
| #endif // __Fuchsia__ |
| Clone(const T& value, T* result) { |
| return value.Clone(result); |
| } |
| |
| #ifdef __Fuchsia__ |
| template <typename T> |
| zx_status_t Clone(const zx::object<T>& value, zx::object<T>* result) { |
| if (!value) { |
| result->reset(); |
| return ZX_OK; |
| } |
| return internal::CloneKernelObject(value, result); |
| } |
| #endif // __Fuchsia__ |
| |
| zx_status_t Clone(const StringPtr& value, StringPtr* result); |
| zx_status_t Clone(const ::std::string& value, std::string* result); |
| |
| template <typename T> |
| inline zx_status_t Clone(const std::unique_ptr<T>& value, std::unique_ptr<T>* result) { |
| if (!value) { |
| result->reset(); |
| return ZX_OK; |
| } |
| *result = std::make_unique<T>(); |
| return Clone(*value, result->get()); |
| } |
| |
| template <typename T> |
| inline typename std::enable_if<IsPrimitive<T>::value || IsStdString<T>::value, zx_status_t>::type |
| Clone(const VectorPtr<T>& value, VectorPtr<T>* result) { |
| if (!value.has_value()) { |
| result->reset(); |
| return ZX_OK; |
| } |
| *result = *value; |
| return ZX_OK; |
| } |
| |
| template <typename T> |
| inline typename std::enable_if<IsPrimitive<T>::value || IsStdString<T>::value, zx_status_t>::type |
| Clone(const ::std::vector<T>& value, ::std::vector<T>* result) { |
| *result = value; |
| return ZX_OK; |
| } |
| |
| template <typename T> |
| inline typename std::enable_if<!IsPrimitive<T>::value && !IsStdString<T>::value, zx_status_t>::type |
| Clone(const ::std::vector<T>& value, ::std::vector<T>* result) { |
| result->resize(value.size()); |
| for (size_t i = 0; i < value.size(); ++i) { |
| zx_status_t status = Clone(value.at(i), &result->at(i)); |
| if (status != ZX_OK) |
| return status; |
| } |
| return ZX_OK; |
| } |
| |
| template <typename T> |
| inline typename std::enable_if<!IsPrimitive<T>::value && !IsStdString<T>::value, zx_status_t>::type |
| Clone(const VectorPtr<T>& value, VectorPtr<T>* result) { |
| if (!value.has_value()) { |
| result->reset(); |
| return ZX_OK; |
| } |
| result->emplace(); |
| (*result)->resize(value->size()); |
| for (size_t i = 0; i < value->size(); ++i) { |
| zx_status_t status = Clone(value->at(i), &(*result)->at(i)); |
| if (status != ZX_OK) |
| return status; |
| } |
| return ZX_OK; |
| } |
| |
| template <typename T, size_t N> |
| inline typename std::enable_if<IsPrimitive<T>::value || IsStdString<T>::value, zx_status_t>::type |
| Clone(const ::std::array<T, N>& value, ::std::array<T, N>* result) { |
| *result = value; |
| return ZX_OK; |
| } |
| |
| template <typename T, size_t N> |
| inline typename std::enable_if<!IsPrimitive<T>::value && !IsStdString<T>::value, zx_status_t>::type |
| Clone(const std::array<T, N>& value, std::array<T, N>* result) { |
| for (size_t i = 0; i < N; ++i) { |
| zx_status_t status = Clone(value[i], &result->at(i)); |
| if (status != ZX_OK) |
| return status; |
| } |
| return ZX_OK; |
| } |
| |
| inline zx_status_t Clone(const UnknownBytes& value, UnknownBytes* result) { |
| result->bytes = value.bytes; |
| return ZX_OK; |
| } |
| |
| inline zx_status_t Clone(const ::std::map<uint64_t, ::std::vector<uint8_t>>& value, |
| ::std::map<uint64_t, ::std::vector<uint8_t>>* result) { |
| *result = value; |
| return ZX_OK; |
| } |
| |
| #ifdef __Fuchsia__ |
| inline zx_status_t Clone(const UnknownData& value, UnknownData* result) { |
| result->bytes = value.bytes; |
| return Clone(value.handles, &(result->handles)); |
| } |
| |
| inline zx_status_t Clone(const ::std::map<uint64_t, UnknownData>& value, |
| ::std::map<uint64_t, UnknownData>* result) { |
| result->clear(); |
| for (const auto& pair : value) { |
| auto field = result->emplace(std::piecewise_construct, std::forward_as_tuple(pair.first), |
| std::forward_as_tuple()); |
| zx_status_t status = Clone(pair.second, &field.first->second); |
| if (status != ZX_OK) |
| return status; |
| } |
| return ZX_OK; |
| } |
| #endif |
| |
| // Returns a deep copy of |value|. |
| // This operation also attempts to duplicate any handles the value contains. |
| // |
| // Crashes the program if the value could not be cloned, perhaps because a |
| // handle was not duplicable. |
| template <typename T> |
| inline T Clone(const T& value) { |
| T clone; |
| zx_status_t status = Clone(value, &clone); |
| ZX_ASSERT(status == ZX_OK); |
| return clone; |
| } |
| |
| } // namespace fidl |
| |
| #endif // LIB_FIDL_CPP_CLONE_H_ |