blob: 701803dbb26ee27ee13953b3eb4e593e4f656390 [file] [log] [blame]
// 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_