// Copyright 2016 The Chromium 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 MOJO_PUBLIC_CPP_BINDINGS_STL_CONVERTERS_H_ #define MOJO_PUBLIC_CPP_BINDINGS_STL_CONVERTERS_H_ #include #include #include #include #include "mojo/public/cpp/bindings/array.h" #include "mojo/public/cpp/bindings/map.h" #include "mojo/public/cpp/bindings/string.h" // Two functions are defined to facilitate conversion between // mojo::Array/Map/String and std::vector/map/string: mojo::UnwrapToSTLType() // recursively convert mojo types to STL types; mojo::WrapSTLType() does the // opposite. For example: // mojo::Array>> mojo_obj; // // std::vector>> stl_obj = // mojo::UnwrapToSTLType(std::move(mojo_obj)); // // mojo_obj = mojo::WrapSTLType(std::move(stl_obj)); // // Notes: // - The conversion moves as much contents as possible. The two functions both // take an rvalue ref as input in order to avoid accidental copies. // - Because std::vector/map/string cannot express null, UnwrapToSTLType() // converts null mojo::Array/Map/String to empty. // - The recursive conversion stops at any types that are not the types listed // above. For example, unwrapping mojo::Array will // result in std::vector. It won't convert // mojo::Map inside the struct. namespace mojo { namespace internal { template struct UnwrapTraits; template struct UnwrapShouldGoDeeper { public: static const bool value = !std::is_same::Type>::value; }; template struct UnwrapTraits { public: using Type = T; static Type Unwrap(T input) { return input; } }; template struct UnwrapTraits> { public: using Type = std::vector::Type>; static Type Unwrap(Array input) { return Helper::Run(std::move(input)); } private: template ::value> struct Helper {}; template struct Helper { public: static Type Run(Array input) { Type output; output.reserve(input.size()); for (size_t i = 0; i < input.size(); ++i) output.push_back(UnwrapTraits::Unwrap(std::move(input[i]))); return output; } }; template struct Helper { public: static Type Run(Array input) { return input.PassStorage(); } }; }; template struct UnwrapTraits> { public: using Type = std::map::Type, typename UnwrapTraits::Type>; static Type Unwrap(Map input) { return Helper::Run(std::move(input)); } private: template ::value || UnwrapShouldGoDeeper::value> struct Helper {}; template struct Helper { public: static Type Run(Map input) { std::map input_storage = input.PassStorage(); Type output; for (auto& pair : input_storage) { output.insert( std::make_pair(UnwrapTraits::Unwrap(pair.first), UnwrapTraits::Unwrap(std::move(pair.second)))); } return output; } }; template struct Helper { public: static Type Run(Map input) { return input.PassStorage(); } }; }; template <> struct UnwrapTraits { public: using Type = std::string; static std::string Unwrap(const String& input) { return input; } }; template struct WrapTraits; template struct WrapShouldGoDeeper { public: static const bool value = !std::is_same::Type>::value; }; template struct WrapTraits { public: using Type = T; static T Wrap(T input) { return input; } }; template struct WrapTraits> { public: using Type = Array::Type>; static Type Wrap(std::vector input) { return Helper::Run(std::move(input)); } private: template ::value> struct Helper {}; template struct Helper { public: static Type Run(std::vector input) { std::vector::Type> output_storage; output_storage.reserve(input.size()); for (auto& element : input) output_storage.push_back(WrapTraits::Wrap(std::move(element))); return Type(std::move(output_storage)); } }; template struct Helper { public: static Type Run(std::vector input) { return Type(std::move(input)); } }; }; template struct WrapTraits> { public: using Type = Map::Type, typename WrapTraits::Type>; static Type Wrap(std::map input) { return Helper::Run(std::move(input)); } private: template ::value || WrapShouldGoDeeper::value> struct Helper {}; template struct Helper { public: static Type Run(std::map input) { Type output; for (auto& pair : input) { output.insert(WrapTraits::Wrap(pair.first), WrapTraits::Wrap(std::move(pair.second))); } return output; } }; template struct Helper { public: static Type Run(std::map input) { return Type(std::move(input)); } }; }; template <> struct WrapTraits { public: using Type = String; static String Wrap(const std::string& input) { return input; } }; } // namespace internal template typename internal::UnwrapTraits::Type UnwrapToSTLType(T&& input) { return internal::UnwrapTraits::Unwrap(std::move(input)); } template typename internal::WrapTraits::Type WrapSTLType(T&& input) { return internal::WrapTraits::Wrap(std::move(input)); } } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_STL_CONVERTERS_H_