| // Copyright 2022 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 SRC_LIB_FIDL_CPP_INCLUDE_LIB_FIDL_CPP_WIRE_NATURAL_CONVERSIONS_H_ |
| #define SRC_LIB_FIDL_CPP_INCLUDE_LIB_FIDL_CPP_WIRE_NATURAL_CONVERSIONS_H_ |
| |
| #include <lib/fidl/cpp/box.h> |
| #include <lib/fidl/cpp/wire/object_view.h> |
| #include <lib/fidl/cpp/wire/optional.h> |
| #include <lib/fidl/cpp/wire/string_view.h> |
| #include <lib/fidl/cpp/wire/traits.h> |
| #include <lib/fidl/cpp/wire/vector_view.h> |
| |
| #include <type_traits> |
| |
| namespace fidl { |
| namespace internal { |
| |
| // The base case for |NaturalTypeForWireType| prints an error. |
| // Generated code should specialize this template for generated wire types. |
| template <typename WireType, typename Enable = void> |
| struct NaturalTypeForWireType { |
| // A type-dependent expression to help emit a static_assert error only when we |
| // hit this template specialization base case. `static_assert(false);` does |
| // not work because the compiler will eagerly fail. |T| is not used otherwise. |
| template <typename... T> |
| static constexpr bool kDoesNotKnowHowToConvertThisType = false; |
| static_assert(kDoesNotKnowHowToConvertThisType<WireType>, |
| "Does not know how to convert this type to its corresponding natural type. " |
| "Make sure to include the FIDL headers for natural types. " |
| "The #include pattern looks like #include <fidl/my.library/cpp/fidl.h>"); |
| using type = WireType; |
| }; |
| |
| // The base case for |WireTypeForNaturalType| prints an error. |
| // Generated code should specialize this template for generated natural types. |
| template <typename NaturalType, typename Enable = void> |
| struct WireTypeForNaturalType { |
| // A type-dependent expression to help emit a static_assert error only when we |
| // hit this template specialization base case. `static_assert(false);` does |
| // not work because the compiler will eagerly fail. |T| is not used otherwise. |
| template <typename... T> |
| static constexpr bool kDoesNotKnowHowToConvertThisType = false; |
| static_assert(kDoesNotKnowHowToConvertThisType<NaturalType>, |
| "Does not know how to convert this type to its corresponding wire type. " |
| "Make sure to include the FIDL headers for natural types. " |
| "The #include pattern looks like #include <fidl/my.library/cpp/fidl.h>"); |
| using type = NaturalType; |
| }; |
| |
| // Specialize for primitive types. |
| template <typename T> |
| struct NaturalTypeForWireType<T, std::enable_if_t<std::is_arithmetic_v<T>>> { |
| using type = T; |
| }; |
| template <typename T> |
| struct WireTypeForNaturalType<T, std::enable_if_t<std::is_arithmetic_v<T>>> { |
| using type = T; |
| }; |
| |
| template <typename WireType, typename NaturalType> |
| struct WireNaturalConversionTraits; |
| |
| template <typename T> |
| struct WireNaturalConversionTraits<T, T> { |
| static T ToNatural(T src) { return std::move(src); } |
| static T ToWire(fidl::AnyArena&, T src) { return std::move(src); } |
| }; |
| |
| template <> |
| struct WireNaturalConversionTraits<fidl::StringView, std::string> { |
| static std::string ToNatural(fidl::StringView src) { return std::string(src.data(), src.size()); } |
| static fidl::StringView ToWire(fidl::AnyArena& arena, std::string src) { |
| return fidl::StringView(arena, src); |
| } |
| }; |
| |
| template <> |
| struct WireNaturalConversionTraits<fidl::StringView, std::optional<std::string>> { |
| static std::optional<std::string> ToNatural(fidl::StringView src) { |
| if (!src.data()) { |
| return std::nullopt; |
| } |
| return WireNaturalConversionTraits<fidl::StringView, std::string>::ToNatural(src); |
| } |
| static fidl::StringView ToWire(fidl::AnyArena& arena, std::optional<std::string> src) { |
| if (!src.has_value()) { |
| return fidl::StringView::FromExternal(nullptr, 0); |
| } |
| return WireNaturalConversionTraits<fidl::StringView, std::string>::ToWire(arena, src.value()); |
| } |
| }; |
| |
| template <> |
| struct NaturalTypeForWireType<fidl::StringView> { |
| using type = std::optional<std::string>; |
| }; |
| template <> |
| struct WireTypeForNaturalType<std::string> { |
| using type = fidl::StringView; |
| }; |
| template <> |
| struct WireTypeForNaturalType<std::optional<std::string>> { |
| using type = fidl::StringView; |
| }; |
| |
| template <typename WireType, typename NaturalType> |
| struct WireNaturalConversionTraits<fidl::VectorView<WireType>, std::vector<NaturalType>> { |
| static std::vector<NaturalType> ToNatural(fidl::VectorView<WireType> src) { |
| std::vector<NaturalType> vec; |
| vec.reserve(src.count()); |
| for (uint32_t i = 0; i < src.count(); i++) { |
| vec.push_back( |
| WireNaturalConversionTraits<WireType, NaturalType>::ToNatural(std::move(src[i]))); |
| } |
| return std::move(vec); |
| } |
| static fidl::VectorView<WireType> ToWire(fidl::AnyArena& arena, std::vector<NaturalType> src) { |
| fidl::VectorView<WireType> vec(arena, src.size()); |
| for (uint32_t i = 0; i < src.size(); i++) { |
| vec[i] = WireNaturalConversionTraits<WireType, NaturalType>::ToWire(arena, std::move(src[i])); |
| } |
| return std::move(vec); |
| } |
| }; |
| |
| template <typename WireType, typename NaturalType> |
| struct WireNaturalConversionTraits<fidl::VectorView<WireType>, |
| std::optional<std::vector<NaturalType>>> { |
| static std::optional<std::vector<NaturalType>> ToNatural(fidl::VectorView<WireType> src) { |
| if (!src.data()) { |
| return std::nullopt; |
| } |
| return WireNaturalConversionTraits<fidl::VectorView<WireType>, |
| std::vector<NaturalType>>::ToNatural(src); |
| } |
| static fidl::VectorView<WireType> ToWire(fidl::AnyArena& arena, |
| std::optional<std::vector<NaturalType>> src) { |
| if (!src.has_value()) { |
| return fidl::VectorView<WireType>(); |
| } |
| return WireNaturalConversionTraits<fidl::VectorView<WireType>, |
| std::vector<NaturalType>>::ToWire(arena, |
| std::move(src.value())); |
| } |
| }; |
| |
| template <typename WireType> |
| struct NaturalTypeForWireType<fidl::VectorView<WireType>> { |
| using type = std::optional<std::vector<typename NaturalTypeForWireType<WireType>::type>>; |
| }; |
| template <typename NaturalType> |
| struct WireTypeForNaturalType<std::vector<NaturalType>> { |
| using type = fidl::VectorView<typename WireTypeForNaturalType<NaturalType>::type>; |
| }; |
| template <typename NaturalType> |
| struct WireTypeForNaturalType<std::optional<std::vector<NaturalType>>> { |
| using type = fidl::VectorView<typename WireTypeForNaturalType<NaturalType>::type>; |
| }; |
| |
| template <typename WireType, typename NaturalType, size_t N> |
| struct WireNaturalConversionTraits<fidl::Array<WireType, N>, std::array<NaturalType, N>> { |
| static std::array<NaturalType, N> ToNatural(fidl::Array<WireType, N> src) { |
| return ArrayToNaturalHelper(std::move(src), std::make_index_sequence<N>()); |
| } |
| template <std::size_t... Indexes> |
| static std::array<NaturalType, N> ArrayToNaturalHelper(fidl::Array<WireType, N> value, |
| std::index_sequence<Indexes...>) { |
| return std::array<NaturalType, N>{WireNaturalConversionTraits<WireType, NaturalType>::ToNatural( |
| std::move(value[Indexes]))...}; |
| } |
| |
| static fidl::Array<WireType, N> ToWire(fidl::AnyArena& arena, std::array<NaturalType, N> src) { |
| return ArrayToWireHelper(arena, std::move(src), std::make_index_sequence<N>()); |
| } |
| template <std::size_t... Indexes> |
| static fidl::Array<WireType, N> ArrayToWireHelper(fidl::AnyArena& arena, |
| std::array<NaturalType, N> value, |
| std::index_sequence<Indexes...>) { |
| return fidl::Array<WireType, N>{WireNaturalConversionTraits<WireType, NaturalType>::ToWire( |
| arena, std::move(value[Indexes]))...}; |
| } |
| }; |
| |
| template <typename WireType, size_t N> |
| struct NaturalTypeForWireType<fidl::Array<WireType, N>> { |
| using type = std::array<typename NaturalTypeForWireType<WireType>::type, N>; |
| }; |
| template <typename NaturalType, size_t N> |
| struct WireTypeForNaturalType<std::array<NaturalType, N>> { |
| using type = fidl::Array<typename WireTypeForNaturalType<NaturalType>::type, N>; |
| }; |
| |
| template <typename WireType, typename NaturalType> |
| struct WireNaturalConversionTraits<fidl::ObjectView<WireType>, fidl::Box<NaturalType>> { |
| static fidl::Box<NaturalType> ToNatural(fidl::ObjectView<WireType> src) { |
| if (!src) { |
| return nullptr; |
| } |
| return std::make_unique<NaturalType>( |
| WireNaturalConversionTraits<WireType, NaturalType>::ToNatural(std::move(*src))); |
| } |
| static fidl::ObjectView<WireType> ToWire(fidl::AnyArena& arena, fidl::Box<NaturalType> src) { |
| if (!src) { |
| return nullptr; |
| } |
| return fidl::ObjectView<WireType>( |
| arena, WireNaturalConversionTraits<WireType, NaturalType>::ToWire(arena, std::move(*src))); |
| } |
| }; |
| |
| template <typename WireType, typename NaturalType> |
| struct WireNaturalConversionTraits<fidl::WireOptional<WireType>, fidl::Box<NaturalType>> { |
| static fidl::Box<NaturalType> ToNatural(fidl::WireOptional<WireType> src) { |
| if (!src.has_value()) { |
| return nullptr; |
| } |
| return std::make_unique<NaturalType>( |
| WireNaturalConversionTraits<WireType, NaturalType>::ToNatural(std::move(*src))); |
| } |
| static fidl::WireOptional<WireType> ToWire(fidl::AnyArena& arena, fidl::Box<NaturalType> src) { |
| if (!src) { |
| return {}; |
| } |
| return WireNaturalConversionTraits<WireType, NaturalType>::ToWire(arena, std::move(*src)); |
| } |
| }; |
| |
| template <typename WireType> |
| struct NaturalTypeForWireType<fidl::ObjectView<WireType>> { |
| using type = fidl::Box<typename NaturalTypeForWireType<WireType>::type>; |
| }; |
| template <typename NaturalType> |
| struct WireTypeForNaturalType<fidl::Box<NaturalType>, |
| std::enable_if_t<!IsUnion<NaturalType>::value>> { |
| using type = fidl::ObjectView<typename WireTypeForNaturalType<NaturalType>::type>; |
| }; |
| |
| template <typename WireType> |
| struct NaturalTypeForWireType<fidl::WireOptional<WireType>> { |
| using type = fidl::Box<typename NaturalTypeForWireType<WireType>::type>; |
| }; |
| template <typename NaturalType> |
| struct WireTypeForNaturalType<fidl::Box<NaturalType>, |
| std::enable_if_t<IsUnion<NaturalType>::value>> { |
| using type = fidl::WireOptional<typename WireTypeForNaturalType<NaturalType>::type>; |
| }; |
| |
| template <typename WireResultType, typename NaturalErrorType, typename NaturalValueType> |
| struct WireNaturalConversionTraits<WireResultType, |
| fit::result<NaturalErrorType, NaturalValueType>> { |
| static fit::result<NaturalErrorType, NaturalValueType> ToNatural(WireResultType src) { |
| if (src.is_err()) { |
| using WireErrorType = std::remove_reference_t<decltype(src.err())>; |
| return fit::error<NaturalErrorType>( |
| WireNaturalConversionTraits<WireErrorType, NaturalErrorType>::ToNatural( |
| std::move(src.err()))); |
| } |
| using WireValueType = std::remove_reference_t<decltype(src.response())>; |
| return fit::ok<NaturalValueType>( |
| WireNaturalConversionTraits<WireValueType, NaturalValueType>::ToNatural( |
| std::move(src.response()))); |
| } |
| static WireResultType ToWire(fidl::AnyArena& arena, |
| fit::result<NaturalErrorType, NaturalValueType> src) { |
| if (src.is_error()) { |
| return WireResultType::WithErr( |
| WireNaturalConversionTraits<typename WireTypeForNaturalType<NaturalErrorType>::type, |
| NaturalErrorType>::ToWire(arena, |
| std::move(src.error_value()))); |
| } |
| if constexpr (sizeof(typename WireTypeForNaturalType<NaturalValueType>::type) <= |
| FIDL_ENVELOPE_INLINING_SIZE_THRESHOLD) { |
| return WireResultType::WithResponse( |
| WireNaturalConversionTraits<typename WireTypeForNaturalType<NaturalValueType>::type, |
| NaturalValueType>::ToWire(arena, std::move(src.value()))); |
| } else { |
| return WireResultType::WithResponse( |
| arena, |
| WireNaturalConversionTraits<typename WireTypeForNaturalType<NaturalValueType>::type, |
| NaturalValueType>::ToWire(arena, std::move(src.value()))); |
| } |
| } |
| }; |
| |
| template <typename WireResultType, typename NaturalErrorType> |
| struct WireNaturalConversionTraits<WireResultType, fit::result<NaturalErrorType>> { |
| static fit::result<NaturalErrorType> ToNatural(WireResultType src) { |
| if (src.is_err()) { |
| using WireErrorType = std::remove_reference_t<decltype(src.err())>; |
| return fit::error<NaturalErrorType>( |
| WireNaturalConversionTraits<WireErrorType, NaturalErrorType>::ToNatural( |
| std::move(src.err()))); |
| } |
| return fit::ok(); |
| } |
| static WireResultType ToWire(fidl::AnyArena& arena, fit::result<NaturalErrorType> src) { |
| if (src.is_error()) { |
| return WireResultType::WithErr( |
| WireNaturalConversionTraits<typename WireTypeForNaturalType<NaturalErrorType>::type, |
| NaturalErrorType>::ToWire(arena, |
| std::move(src.error_value()))); |
| } |
| return WireResultType::WithResponse({}); |
| } |
| }; |
| |
| template <typename NaturalType, typename WireType> |
| NaturalType ToNatural(WireType value) { |
| return internal::WireNaturalConversionTraits<WireType, NaturalType>::ToNatural(std::move(value)); |
| } |
| |
| template <typename WireType, typename NaturalType> |
| WireType ToWire(fidl::AnyArena& arena, NaturalType value) { |
| return internal::WireNaturalConversionTraits<WireType, NaturalType>::ToWire(arena, |
| std::move(value)); |
| } |
| |
| } // namespace internal |
| |
| // fidl::ToNatural(wire_value) -> natural_value |
| // |
| // ToNatural is a converter from wire types to natural types. |
| // ToNatural will succeed so long as the input data is valid (e.g. no bad pointers). |
| // In cases where the natural type is ambiguous due to optionality, the optional version |
| // of the type will be returned. |
| template <typename WireType> |
| auto ToNatural(WireType value) { |
| using DecayedWire = std::remove_cv_t<std::remove_reference_t<WireType>>; |
| return internal::ToNatural<typename internal::NaturalTypeForWireType<DecayedWire>::type, |
| DecayedWire>(std::move(value)); |
| } |
| |
| // fidl::ToWire(natural_value, arena) -> wire_value |
| // |
| // ToWire is a converter from wire types to natural types. |
| // ToWire will succeed so long as the input data is valid (e.g. no bad pointers). |
| // |
| // All out-of-line values will be copied to |arena|. |
| template <typename NaturalType> |
| auto ToWire(fidl::AnyArena& arena, NaturalType value) { |
| using DecayedNatural = std::remove_cv_t<std::remove_reference_t<NaturalType>>; |
| return internal::ToWire<typename internal::WireTypeForNaturalType<DecayedNatural>::type, |
| DecayedNatural>(arena, std::move(value)); |
| } |
| |
| } // namespace fidl |
| |
| #endif // SRC_LIB_FIDL_CPP_INCLUDE_LIB_FIDL_CPP_WIRE_NATURAL_CONVERSIONS_H_ |