blob: f51599af956de01cdf0766fece5dee5bd903a2b7 [file] [log] [blame]
// 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"
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;
}
// 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_