blob: ae6f16de5a4e5e4300a3a563e88ce178ee5ea56f [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_ERROR_CALLER_INFO_H_
#define LIBHWSEC_FOUNDATION_ERROR_CALLER_INFO_H_
#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include "libhwsec-foundation/error/error.h"
namespace hwsec_foundation {
namespace error {
/* A helper object to include file and line info in the error object.
*
* Example Usage:
*
* using TPM1CallerError = CallerInfoError<TPM1Error>;
*
* auto err = CreateError<TPM1CallerError>(CallerInfoArgs, 0x87);
*
* if (err) {
* LOG(INFO) << *err;
* }
*/
template <typename ErrorType>
class CallerInfoObj : public UnwarpErrorType<ErrorType>::type {
static_assert(is_error_type<ErrorType>::value,
"ErrorType isn't a valid error type.");
public:
using ObjType = typename UnwarpErrorType<ErrorType>::type;
using ErrType = ErrorType;
CallerInfoObj(const char* func, const char* file, int line, ErrorType err)
: ObjType(std::move(*err)), func_(func), file_(file), line_(line) {}
std::string ToReadableString() const override {
return base::StringPrintf("%s:%d %s: %s", file_, line_, func_,
ObjType::ToReadableString().c_str());
}
ErrorBase SelfCopy() const override {
ErrorBase err = ObjType::SelfCopy();
ErrorType convert(dynamic_cast<ObjType*>(err.get()));
if (!convert) {
return nullptr;
}
err.release();
return std::make_unique<CallerInfoObj>(func_, file_, line_,
std::move(convert));
}
private:
const char* const func_;
const char* const file_;
const int line_;
};
template <typename ErrorType>
using CallerInfoError = std::unique_ptr<CallerInfoObj<ErrorType>>;
template <typename ErrorType,
typename std::enable_if<
std::is_base_of<ErrorBaseObj, ErrorType>::value>::type* = nullptr>
std::true_type is_caller_info_error_type_impl(const CallerInfoObj<ErrorType>&);
template <typename T>
std::false_type is_caller_info_error_type_impl(const T&);
template <typename T>
using is_caller_info_error_type =
decltype(is_caller_info_error_type_impl(std::declval<T>()));
template <
typename CallerInfoErrorType,
typename... Args,
typename is_caller_info_error_type<CallerInfoErrorType>::type* = nullptr,
decltype(typename UnwarpErrorType<CallerInfoErrorType>::type::ObjType(
std::forward<Args>(std::declval<Args&&>())...))* = nullptr>
CallerInfoErrorType CreateError(const char* func,
const char* file,
int line,
Args&&... args) {
auto result =
CreateError<typename UnwarpErrorType<CallerInfoErrorType>::type::ErrType>(
std::forward<Args>(args)...);
if (!result) {
return nullptr;
}
return std::make_unique<CallerInfoObj<
typename UnwarpErrorType<CallerInfoErrorType>::type::ErrType>>(
func, file, line, std::move(result));
}
#define CALLER_INFO_ARGS __func__, __FILE__, __LINE__
} // namespace error
} // namespace hwsec_foundation
#endif // LIBHWSEC_FOUNDATION_ERROR_CALLER_INFO_H_