| // 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_ANY_ERROR_IN_H_ |
| #define SRC_LIB_FIDL_CPP_INCLUDE_LIB_FIDL_CPP_ANY_ERROR_IN_H_ |
| |
| #include <lib/fidl/cpp/unified_messaging.h> |
| #include <lib/fidl/llcpp/status.h> |
| #include <lib/fit/function.h> |
| #include <lib/stdcompat/string_view.h> |
| #include <lib/stdcompat/variant.h> |
| |
| #include <array> |
| #include <string> |
| |
| namespace fidl { |
| namespace internal { |
| |
| // A helper to erase the |ApplicationError| template type and share the common |
| // printing logic. |
| class AnyErrorInBase { |
| protected: |
| using FormattingBuffer = std::array<char, 512>; |
| |
| // |prelude| will be printed first. |
| // |display_error| invokes the |DisplayError<T>| specialization. |
| // Returns how many bytes are written, excluding the NUL terminator. |
| static size_t FormatImpl(const char* prelude, FormattingBuffer& buffer, |
| fit::inline_callback<size_t(char*, size_t)> display_error); |
| |
| template <typename ApplicationError> |
| static size_t Format(FormattingBuffer& buffer, |
| const cpp17::variant<fidl::Error, ApplicationError>& error) { |
| return FormatImpl(Prelude(error), buffer, [&](char* destination, size_t capacity) { |
| return std::visit( |
| [&](auto&& error) { return FormatDisplayError(error, destination, capacity); }, error); |
| }); |
| } |
| |
| private: |
| template <typename ApplicationError> |
| static const char* Prelude(const cpp17::variant<fidl::Error, ApplicationError>& error) { |
| switch (error.index()) { |
| case 0: |
| return kTransportErrorPrelude; |
| case 1: |
| return kApplicationErrorPrelude; |
| default: |
| __builtin_trap(); |
| } |
| } |
| |
| static const char* kTransportErrorPrelude; |
| static const char* kApplicationErrorPrelude; |
| }; |
| |
| // |AnyErrorInImpl| is used to implement |AnyErrorIn|. |
| // |
| // |ApplicationError| must be a domain object generated by the FIDL toolchain. |
| // |ApplicationError| must be int32, uint32, or an enum of one of those types. |
| template <typename ApplicationError> |
| class AnyErrorInImpl : private AnyErrorInBase { |
| public: |
| explicit AnyErrorInImpl(fidl::Error transport_error) : error_(transport_error) {} |
| explicit AnyErrorInImpl(ApplicationError application_error) : error_(application_error) {} |
| |
| bool is_transport_error() const { return cpp17::holds_alternative<fidl::Error>(error_); } |
| const fidl::Error& transport_error() const { return cpp17::get<fidl::Error>(error_); } |
| fidl::Error& transport_error() { return cpp17::get<fidl::Error>(error_); } |
| |
| bool is_application_error() const { return cpp17::holds_alternative<ApplicationError>(error_); } |
| const ApplicationError& application_error() const { return cpp17::get<ApplicationError>(error_); } |
| ApplicationError& application_error() { return cpp17::get<ApplicationError>(error_); } |
| |
| // Prints a description of the error. |
| // |
| // If a logging API supports output streams (`<<` operators), piping the |
| // error to the log via `<<` is more efficient than calling this function. |
| std::string FormatDescription() const { |
| FormattingBuffer buffer; |
| size_t length = Format(buffer, error_); |
| return std::string(buffer.begin(), length); |
| } |
| |
| private: |
| friend std::ostream& operator<<(std::ostream& ostream, const AnyErrorInImpl& any_error) { |
| FormattingBuffer buffer; |
| size_t length = Format(buffer, any_error.error_); |
| ostream << cpp17::string_view(buffer.begin(), length); |
| return ostream; |
| } |
| |
| cpp17::variant<fidl::Error, ApplicationError> error_; |
| }; |
| |
| } // namespace internal |
| |
| // |AnyErrorIn<Method>| represents the set of all possible errors during a |
| // fallible two-way |Method|: |
| // |
| // - Transport errors. |
| // - Application errors in the |Method| error syntax. |
| // |
| // Users should first inspect if an instance contains a transport or application |
| // error, before diving into the individual variant. Alternatively, they may |
| // print a description either by piping it to an |std::ostream| or calling |
| // |FormatDescription|. |
| template <typename FidlMethod> |
| class AnyErrorIn : public internal::AnyErrorInImpl<internal::NaturalApplicationError<FidlMethod>> { |
| public: |
| using internal::AnyErrorInImpl<internal::NaturalApplicationError<FidlMethod>>::AnyErrorInImpl; |
| }; |
| |
| } // namespace fidl |
| |
| #endif // SRC_LIB_FIDL_CPP_INCLUDE_LIB_FIDL_CPP_ANY_ERROR_IN_H_ |