blob: 491ac4689d5fedd934a79d7c3e1abc9c4a292ec7 [file] [log] [blame]
// Copyright 2021 The Chromium OS 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 LIBHWSEC_FOUNDATION_STATUS_STATUS_CHAIN_H_
#define LIBHWSEC_FOUNDATION_STATUS_STATUS_CHAIN_H_
#include <iostream>
#include <string>
#include <type_traits>
#include <utility>
// error.h is the finalized header, do not include any other impl headers
// directly.
#include "libhwsec-foundation/status/impl/error.h"
namespace hwsec_foundation {
namespace status {
// Trait check for being a |StatusChain| holding type.
namespace __impl {
template <typename T>
std::false_type __is_status_chain(const T&);
// |StackableError| is aliased as |StatusChain| bellow.
template <typename _Et>
std::true_type __is_status_chain(const StackableError<_Et>&);
} // namespace __impl
// Alias the traits to be publicly visible.
template <typename T>
using is_status_chain = decltype(__impl::__is_status_chain(std::declval<T>()));
template <typename T>
constexpr inline bool is_status_chain_v = is_status_chain<T>::value;
template <typename _Et>
using has_make_status_trait = __impl::has_make_status_trait<_Et>;
template <typename _Et>
inline constexpr bool has_make_status_trait_v =
__impl::has_make_status_trait_v<_Et>;
template <typename _Et>
using has_base_error_type = __impl::has_base_error_type<_Et>;
template <typename _Et>
inline constexpr bool has_base_error_type_v =
__impl::has_base_error_type_v<_Et>;
// Declare base |Error| type
using Error = __impl::Error;
// |StackableError| is the canonical Status holder for use in hwsec. Alias it
// to a Status resambling name.
template <typename _Et>
using StatusChain = __impl::StackableError<_Et>;
// Make a usable discard tag.
constexpr __impl::WrapTransformOnly WrapTransformOnly;
// Creates a new error object, wrapped in |StatusChain|. Custom overloads for
// error types may return a different object type, that might need to be dealt
// with in a certain way to get an object convertible to status type.
template <typename _Et, typename... Args>
auto MakeStatus(Args&&... args) {
static_assert(std::is_base_of_v<Error, _Et> || std::is_same_v<Error, _Et>,
"Supplied type is not derived from |Error|.");
using MakeStatusTrait = typename _Et::MakeStatusTrait;
return MakeStatusTrait()(std::forward<Args>(args)...);
}
// Factory function for |StatusChain| which by-passes the trait overload for
// creating a status. While it is not enforceable, this function should ONLY be
// used from inside |MakeStatusTrait| customization.
template <typename _Et, typename... Args>
StatusChain<_Et> NewStatus(Args&&... args) {
static_assert(std::is_base_of_v<Error, _Et> || std::is_same_v<Error, _Et>,
"Supplied type is not derived from |Error|.");
return StatusChain<_Et>(new _Et(std::forward<Args>(args)...));
}
// Return |nullptr| error object in a typed |StatusChain| container.
template <typename _Et>
StatusChain<_Et> OkStatus() {
static_assert(std::is_base_of_v<Error, _Et> || std::is_same_v<Error, _Et>,
"Supplied type is not derived from |Error|.");
return StatusChain<_Et>(nullptr);
}
// Return |nullptr| error object in a typed |const StatusChain| container.
template <typename _Et>
const StatusChain<_Et>& ConstRefOkStatus() {
// thread_local variable instances are initialized much like static
// variables, except that they must be initialized separately for each
// thread, rather than once at program startup. This means that
// thread_local variables declared within a function are safe.
// thread_local variable instances are not destroyed before their thread
// terminates, so they do not have the destruction-order issues of static
// variables.
const thread_local StatusChain<_Et> kOkStatus = OkStatus<_Et>();
return kOkStatus;
}
// Specifies default behaviour of the MakeStatus on the object. Default is to
// pass the arguments to the constructor of |_Et|.
template <typename _Et>
struct DefaultMakeStatus {
template <typename... Args>
auto operator()(Args&&... args) {
return StatusChain<_Et>(new _Et(std::forward<Args>(args)...));
}
};
// Forbids MakeStatus on the object.
struct ForbidMakeStatus {};
} // namespace status
} // namespace hwsec_foundation
#endif // LIBHWSEC_FOUNDATION_STATUS_STATUS_CHAIN_H_