| // 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 SRC_LIB_FOSTR_FIDL_TYPES_H_ |
| #define SRC_LIB_FOSTR_FIDL_TYPES_H_ |
| |
| #include <array> |
| #include <sstream> |
| |
| #include "lib/fidl/cpp/framework_err.h" |
| #include "lib/fidl/cpp/vector.h" |
| #include "src/lib/fostr/hex_dump.h" |
| #include "src/lib/fostr/indent.h" |
| |
| #ifdef __Fuchsia__ |
| #include "lib/fidl/cpp/binding.h" |
| #include "lib/fidl/cpp/interface_handle.h" |
| #include "lib/fidl/cpp/interface_ptr.h" |
| #include "lib/fidl/cpp/interface_request.h" |
| #include "src/lib/fostr/zx_types.h" |
| #endif |
| |
| namespace fostr { |
| |
| // Wrapper type to disambiguate formatting operator overloads. |
| // |
| // This file avoids defining any overloads for types in the std namespace. To correctly format |
| // arrays, vectors and unique pointers, this wrapper is used so we can define an overload for |
| // e.g. fostr::Formatted<std::unique_ptr<T>> instead of defining one for std::unique_ptr<T>. |
| // Consequently, this wrapper must be used for the supported std types. The wrapper has no effect |
| // for other types, so it can safely be applied to any value. |
| // |
| // std::vector<int32_t> my_fector; |
| // os << fostr::Formatted(my_vector); |
| // |
| template <typename T> |
| struct Formatted { |
| explicit Formatted(const T& v) : value(v) {} |
| const T& value; |
| }; |
| |
| namespace internal { |
| |
| static constexpr size_t kMaxBytesToDump = 256; |
| static constexpr size_t kTruncatedDumpSize = 64; |
| |
| template <typename Iter> |
| void insert_sequence_container(std::ostream& os, Iter begin, Iter end) { |
| if (begin == end) { |
| os << "<empty>"; |
| } |
| |
| int index = 0; |
| for (; begin != end; ++begin) { |
| os << NewLine << "[" << index++ << "] " << Indent << Formatted(*begin) << Outdent; |
| } |
| } |
| |
| } // namespace internal |
| |
| template <typename T> |
| std::ostream& operator<<(std::ostream& os, const Formatted<T>& value); |
| |
| template <typename T> |
| std::ostream& operator<<(std::ostream& os, const Formatted<T>& value) { |
| return os << value.value; |
| } |
| |
| template <typename T> |
| std::ostream& operator<<(std::ostream& os, const Formatted<std::unique_ptr<T>>& value) { |
| if (!value.value) { |
| return os << "<null>"; |
| } |
| |
| return os << Formatted(*value.value); |
| } |
| |
| template <typename T> |
| std::ostream& operator<<(std::ostream& os, const Formatted<std::vector<T>>& value) { |
| if (value.value.empty()) { |
| return os << "<empty>"; |
| } |
| |
| internal::insert_sequence_container(os, value.value.cbegin(), value.value.cend()); |
| return os; |
| } |
| |
| template <> |
| std::ostream& operator<<(std::ostream& os, const Formatted<std::vector<uint8_t>>& value); |
| |
| template <> |
| std::ostream& operator<<(std::ostream& os, const Formatted<std::vector<int8_t>>& value); |
| |
| template <typename T, size_t N> |
| std::ostream& operator<<(std::ostream& os, const Formatted<std::array<T, N>>& value); |
| |
| template <typename T, size_t N, size_t M> |
| std::ostream& operator<<(std::ostream& os, |
| const Formatted<std::array<std::array<T, M>, N>>& value) { |
| if (value.value.empty()) { |
| return os << "<empty>"; |
| } |
| |
| int index = 0; |
| for (const std::array<T, M>& item : value.value) { // N items |
| os << NewLine << "[" << index++ << "]:" << Indent << Formatted(item) << Outdent; |
| } |
| return os; |
| } |
| |
| template <typename T, size_t N> |
| std::ostream& operator<<(std::ostream& os, const Formatted<std::array<T, N>>& value) { |
| internal::insert_sequence_container(os, value.value.cbegin(), value.value.cend()); |
| return os; |
| } |
| |
| template <size_t N> |
| std::ostream& operator<<(std::ostream& os, const Formatted<std::array<uint8_t, N>>& value) { |
| if (N <= internal::kMaxBytesToDump) { |
| return os << HexDump(value.value.data(), N, 0); |
| } |
| |
| return os << HexDump(value.value.data(), internal::kTruncatedDumpSize, 0) << NewLine |
| << "(truncated, " << N << " bytes total)"; |
| } |
| |
| template <size_t N> |
| std::ostream& operator<<(std::ostream& os, const Formatted<std::array<int8_t, N>>& value) { |
| if (N <= internal::kMaxBytesToDump) { |
| return os << HexDump(value.value.data(), N, 0); |
| } |
| |
| return os << HexDump(value.value.data(), internal::kTruncatedDumpSize, 0) << NewLine |
| << "(truncated, " << N << " bytes total)"; |
| } |
| |
| } // namespace fostr |
| |
| namespace fidl { |
| |
| // ostream operator<< templates for fidl types. These templates conform to the |
| // convention described in indent.h. |
| |
| template <typename T> |
| std::ostream& operator<<(std::ostream& os, const VectorPtr<T>& value) { |
| if (!value.has_value()) { |
| return os << "<null>"; |
| } |
| |
| if (value.value().empty()) { |
| return os << "<empty>"; |
| } |
| |
| fostr::internal::insert_sequence_container(os, value.value().cbegin(), value.value().cend()); |
| return os; |
| } |
| |
| template <> |
| std::ostream& operator<<(std::ostream& os, const VectorPtr<uint8_t>& value); |
| |
| template <> |
| std::ostream& operator<<(std::ostream& os, const VectorPtr<int8_t>& value); |
| |
| inline std::ostream& operator<<(std::ostream& os, const internal::FrameworkErr& value) { |
| if (value == internal::FrameworkErr::kUnknownMethod) { |
| return os << "<unknown method>"; |
| } |
| return os << "<transport error>"; |
| } |
| |
| #ifdef __Fuchsia__ |
| template <typename T> |
| std::ostream& operator<<(std::ostream& os, const Binding<T>& value) { |
| if (!value.is_bound()) { |
| return os << "<not bound>"; |
| } |
| |
| return os << value.channel(); |
| } |
| |
| template <typename T> |
| std::ostream& operator<<(std::ostream& os, const InterfaceHandle<T>& value) { |
| if (!value.is_valid()) { |
| return os << "<not valid>"; |
| } |
| |
| return os << value.channel(); |
| } |
| |
| template <typename T> |
| std::ostream& operator<<(std::ostream& os, const InterfacePtr<T>& value) { |
| if (!value.is_bound()) { |
| return os << "<not bound>"; |
| } |
| |
| return os << value.channel(); |
| } |
| |
| template <typename T> |
| std::ostream& operator<<(std::ostream& os, const InterfaceRequest<T>& value) { |
| if (!value.is_valid()) { |
| return os << "<not valid>"; |
| } |
| |
| return os << value.channel(); |
| } |
| #endif |
| |
| } // namespace fidl |
| |
| #endif // SRC_LIB_FOSTR_FIDL_TYPES_H_ |