Commit 6dbaee56 authored by Dominik Charousset's avatar Dominik Charousset

Use type IDs for error code enums

parent f0041b0e
......@@ -96,14 +96,14 @@ void caf_main(actor_system& sys) {
binary_serializer bs{sys, buf};
auto e = bs(f1);
if (e) {
std::cerr << "*** unable to serialize foo2: " << sys.render(e) << std::endl;
std::cerr << "*** unable to serialize foo2: " << to_string(e) << '\n';
return;
}
// read f2 back from buffer
binary_deserializer bd{sys, buf};
e = bd(f2);
if (e) {
std::cerr << "*** unable to serialize foo2: " << sys.render(e) << std::endl;
std::cerr << "*** unable to serialize foo2: " << to_string(e) << '\n';
return;
}
// must be equal
......
......@@ -242,7 +242,8 @@ public:
actor_registry& registry();
/// Returns a string representation for `err`.
std::string render(const error& x) const;
[[deprecated("please use to_string() on the error")]] std::string
render(const error& x) const;
/// Returns the system-wide group manager.
group_manager& groups();
......
......@@ -67,10 +67,6 @@ public:
using portable_name_map = hash_map<std::type_index, std::string>;
using error_renderer = std::function<std::string(uint8_t, const message&)>;
using error_renderer_map = hash_map<uint8_t, error_renderer>;
using group_module_factory = std::function<group_module*()>;
using group_module_factory_vector = std::vector<group_module_factory>;
......@@ -154,29 +150,6 @@ public:
return add_actor_factory(std::move(name), make_actor_factory(std::move(f)));
}
/// Enables the actor system to convert errors of this error category
/// to human-readable strings via `renderer`.
actor_system_config& add_error_category(uint8_t category, error_renderer f);
/// Enables the actor system to convert errors of this error category
/// to human-readable strings via `to_string(T)`.
template <class T>
actor_system_config&
add_error_category(uint8_t category, string_view category_name) {
auto f = [=](uint8_t val, const std::string& ctx) -> std::string {
std::string result{category_name.begin(), category_name.end()};
result += ": ";
result += to_string(static_cast<T>(val));
if (!ctx.empty()) {
result += " (";
result += ctx;
result += ")";
}
return result;
};
return add_error_category(category, error_renderer{f});
}
/// Loads module `T` with optional template parameters `Ts...`.
template <class T, class... Ts>
actor_system_config& load() {
......@@ -272,10 +245,6 @@ public:
/// @note Has no effect unless building CAF with CAF_ENABLE_ACTOR_PROFILER.
tracing_data_factory* tracing_context = nullptr;
// -- rendering of user-defined types ----------------------------------------
error_renderer_map error_renderers;
// -- parsing parameters -----------------------------------------------------
/// Configures the file path for the INI file, `caf-application.ini` per
......@@ -291,13 +260,8 @@ public:
// -- default error rendering functions --------------------------------------
static std::string render(const error& err);
static std::string render_sec(uint8_t, const message&);
static std::string render_exit_reason(uint8_t, const message&);
static std::string render_pec(uint8_t, const message&);
[[deprecated("please use to_string() on the error")]] static std::string
render(const error& err);
// -- config file parsing ----------------------------------------------------
......
// Deprecated include. The next CAF release won't include this header.
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <type_traits>
namespace caf::detail {
template <class T, std::size_t = sizeof(T)>
std::true_type is_complete_impl(T*);
std::false_type is_complete_impl(...);
/// Checks whether T is a complete type. For example, passing a forward
/// declaration or undefined template specialization evaluates to `false`.
template <class T>
constexpr bool is_complete
= decltype(is_complete_impl(std::declval<T*>()))::value;
} // namespace caf::detail
......@@ -27,6 +27,7 @@
#include <utility>
#include <vector>
#include "caf/detail/is_complete.hpp"
#include "caf/detail/is_one_of.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/fwd.hpp"
......@@ -741,17 +742,6 @@ struct is_stl_tuple_type {
template <class T>
constexpr bool is_stl_tuple_type_v = is_stl_tuple_type<T>::value;
template <class T, std::size_t = sizeof(T)>
std::true_type is_complete_impl(T*);
std::false_type is_complete_impl(...);
/// Checks whether T is a complete type. For example, passing a forward
/// declaration or undefined template specialization evaluates to `false`.
template <class T>
constexpr bool is_complete
= decltype(is_complete_impl(std::declval<T*>()))::value;
} // namespace caf::detail
#undef CAF_HAS_MEMBER_TRAIT
......
......@@ -19,20 +19,21 @@
#pragma once
#include <cstdint>
#include <functional>
#include <memory>
#include <utility>
#include "caf/detail/comparable.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/error_category.hpp"
#include "caf/error_code.hpp"
#include "caf/fwd.hpp"
#include "caf/is_error_code_enum.hpp"
#include "caf/message.hpp"
#include "caf/meta/load_callback.hpp"
#include "caf/meta/omittable_if_empty.hpp"
#include "caf/meta/save_callback.hpp"
#include "caf/meta/type_name.hpp"
#include "caf/none.hpp"
#include "caf/type_id.hpp"
namespace caf {
......@@ -68,38 +69,33 @@ namespace caf {
/// rendering error messages via `actor_system::render(const error&)`.
class CAF_CORE_EXPORT error : detail::comparable<error> {
public:
// -- member types -----------------------------------------------------------
using inspect_fun
= std::function<error(meta::type_name_t, uint8_t&, uint8_t&,
meta::omittable_if_empty_t, message&)>;
// -- constructors, destructors, and assignment operators --------------------
error() noexcept;
error() noexcept = default;
error(none_t) noexcept;
error(error&&) noexcept;
error(error&&) noexcept = default;
error& operator=(error&&) noexcept;
error& operator=(error&&) noexcept = default;
error(const error&);
error& operator=(const error&);
error(uint8_t x, uint8_t y);
error(uint8_t x, uint8_t y, message z);
template <class Enum, class = std::enable_if_t<is_error_code_enum_v<Enum>>>
error(Enum code) : error(static_cast<uint8_t>(code), type_id_v<Enum>) {
// nop
}
template <class Enum, uint8_t Category = error_category<Enum>::value>
error(Enum error_value) : error(static_cast<uint8_t>(error_value), Category) {
template <class Enum, class = std::enable_if_t<is_error_code_enum_v<Enum>>>
error(Enum code, message context)
: error(static_cast<uint8_t>(code), type_id_v<Enum>, std::move(context)) {
// nop
}
template <class Enum>
error(error_code<Enum> code)
: error(static_cast<uint8_t>(code.value()), error_category<Enum>::value) {
error(error_code<Enum> code) : error(to_integer(code), type_id_v<Enum>) {
// nop
}
......@@ -115,21 +111,25 @@ public:
return *this = code.value();
}
~error();
// -- observers --------------------------------------------------------------
// -- properties -------------------------------------------------------------
/// Returns the category-specific error code, whereas `0` means "no error".
/// @pre `*this != none`
uint8_t code() const noexcept;
uint8_t code() const noexcept {
return data_->code;
}
/// Returns the category of this error.
/// Returns the ::type_id of the category for this error.
/// @pre `*this != none`
uint8_t category() const noexcept;
type_id_t category() const noexcept {
return data_->category;
}
/// Returns context information to this error.
/// @pre `*this != none`
const message& context() const noexcept;
const message& context() const noexcept {
return data_->context;
}
/// Returns `*this != none`.
explicit operator bool() const noexcept {
......@@ -143,23 +143,14 @@ public:
int compare(const error&) const noexcept;
int compare(uint8_t x, uint8_t y) const noexcept;
// -- modifiers --------------------------------------------------------------
/// Returns context information to this error.
/// @pre `*this != none`
message& context() noexcept;
/// Sets the error code to 0.
void clear() noexcept;
int compare(uint8_t code, type_id_t category) const noexcept;
// -- static convenience functions -------------------------------------------
/// @cond PRIVATE
static error eval() {
return none;
return error{};
}
template <class F, class... Fs>
......@@ -185,36 +176,39 @@ public:
uint8_t code = 0;
auto cb = meta::load_callback([&] {
if (code == 0) {
x.clear();
x.data_.reset();
if constexpr (std::is_same<result_type, void>::value)
return;
else
return result_type{};
}
x.init();
x.code_ref() = code;
return f(x.category_ref(), x.context());
if (!x.data_)
x.data_.reset(new data);
x.data_->code = code;
return f(x.data_->category, x.data_->context);
});
return f(code, cb);
}
}
private:
// -- inspection support -----------------------------------------------------
uint8_t& code_ref() noexcept;
// -- constructors, destructors, and assignment operators --------------------
uint8_t& category_ref() noexcept;
error(uint8_t code, type_id_t category);
void init();
error(uint8_t code, type_id_t category, message context);
// -- nested classes ---------------------------------------------------------
struct data;
struct data {
uint8_t code;
type_id_t category;
message context;
};
// -- member variables -------------------------------------------------------
data* data_;
std::unique_ptr<data> data_;
};
/// @relates error
......@@ -222,15 +216,15 @@ CAF_CORE_EXPORT std::string to_string(const error& x);
/// @relates error
template <class Enum>
error make_error(Enum code) {
return error{static_cast<uint8_t>(code), error_category<Enum>::value};
std::enable_if_t<is_error_code_enum_v<Enum>, error> make_error(Enum code) {
return error{code};
}
/// @relates error
template <class Enum, class T, class... Ts>
error make_error(Enum code, T&& x, Ts&&... xs) {
return error{static_cast<uint8_t>(code), error_category<Enum>::value,
make_message(std::forward<T>(x), std::forward<Ts>(xs)...)};
std::enable_if_t<is_error_code_enum_v<Enum>, error>
make_error(Enum code, T&& x, Ts&&... xs) {
return error{code, make_message(std::forward<T>(x), std::forward<Ts>(xs)...)};
}
/// @relates error
......@@ -244,15 +238,18 @@ inline bool operator==(none_t, const error& x) {
}
/// @relates error
template <class Enum, uint8_t Category = error_category<Enum>::value>
bool operator==(const error& x, Enum y) {
template <class Enum>
std::enable_if_t<is_error_code_enum_v<Enum>, bool>
operator==(const error& x, Enum y) {
auto code = static_cast<uint8_t>(y);
return code == 0 ? !x : x && x.category() == Category && x.code() == code;
return code == 0 ? !x
: x && x.code() == code && x.category() == type_id_v<Enum>;
}
/// @relates error
template <class Enum, uint8_t Category = error_category<Enum>::value>
bool operator==(Enum x, const error& y) {
template <class Enum>
std::enable_if_t<is_error_code_enum_v<Enum>, bool>
operator==(Enum x, const error& y) {
return y == x;
}
......@@ -267,14 +264,16 @@ inline bool operator!=(none_t, const error& x) {
}
/// @relates error
template <class Enum, uint8_t Category = error_category<Enum>::value>
bool operator!=(const error& x, Enum y) {
template <class Enum>
std::enable_if_t<is_error_code_enum_v<Enum>, bool>
operator!=(const error& x, Enum y) {
return !(x == y);
}
/// @relates error
template <class Enum, uint8_t Category = error_category<Enum>::value>
bool operator!=(Enum x, const error& y) {
template <class Enum>
std::enable_if_t<is_error_code_enum_v<Enum>, bool>
operator!=(Enum x, const error& y) {
return !(x == y);
}
......
......@@ -22,6 +22,7 @@
#include <type_traits>
#include "caf/fwd.hpp"
#include "caf/is_error_code_enum.hpp"
#include "caf/none.hpp"
namespace caf {
......@@ -32,7 +33,11 @@ class error_code {
public:
using enum_type = Enum;
using underlying_type = std::underlying_type_t<enum_type>;
using underlying_type = typename std::underlying_type<enum_type>::type;
static_assert(is_error_code_enum_v<Enum>);
static_assert(std::is_same<underlying_type, uint8_t>::value);
constexpr error_code() noexcept : value_(static_cast<Enum>(0)) {
// nop
......@@ -67,6 +72,12 @@ private:
enum_type value_;
};
/// Returns the value of the underlying integer type of `x`.
template <class Enum, class = std::enable_if_t<is_error_code_enum_v<Enum>>>
constexpr auto to_integer(error_code<Enum> x) noexcept {
return static_cast<typename error_code<Enum>::underlying_type>(x.value());
}
/// Converts `x` to a string if `Enum` provides a `to_string` function.
template <class Enum>
auto to_string(error_code<Enum> x) -> decltype(to_string(x.value())) {
......
......@@ -92,8 +92,8 @@ int exec_main(F fun, int argc, char** argv,
// Pass CLI options to config.
typename helper::config cfg;
if (auto err = cfg.parse(argc, argv, config_file_name)) {
std::cerr << "error while parsing CLI and file options: "
<< actor_system_config::render(err) << std::endl;
std::cerr << "error while parsing CLI and file options: " << to_string(err)
<< std::endl;
return EXIT_FAILURE;
}
// Return immediately if a help text was printed.
......
......@@ -26,7 +26,7 @@
#include <string>
#include "caf/detail/core_export.hpp"
#include "caf/error_category.hpp"
#include "caf/is_error_code_enum.hpp"
namespace caf {
......@@ -56,8 +56,8 @@ enum class exit_reason : uint8_t {
CAF_CORE_EXPORT std::string to_string(exit_reason);
template <>
struct error_category<exit_reason> {
static constexpr uint8_t value = 3;
struct is_error_code_enum<exit_reason> {
static constexpr bool value = true;
};
} // namespace caf
......@@ -27,7 +27,7 @@
#include "caf/deep_to_string.hpp"
#include "caf/error.hpp"
#include "caf/error_category.hpp"
#include "caf/is_error_code_enum.hpp"
#include "caf/unifyn.hpp"
#include "caf/unit.hpp"
......@@ -81,9 +81,9 @@ public:
construct(other);
}
template <class Enum, uint8_t Category = error_category<Enum>::value>
template <class Enum, class = std::enable_if_t<is_error_code_enum_v<Enum>>>
expected(Enum code) : engaged_(false) {
new (std::addressof(error_)) caf::error(make_error(code));
new (std::addressof(error_)) caf::error(code);
}
expected(expected&& other) noexcept(nothrow_move) {
......@@ -157,7 +157,7 @@ public:
return *this;
}
template <class Enum, uint8_t Category = error_category<Enum>::value>
template <class Enum, class = std::enable_if_t<is_error_code_enum_v<Enum>>>
expected& operator=(Enum code) {
return *this = make_error(code);
}
......@@ -298,14 +298,16 @@ bool operator==(const error& x, const expected<T>& y) {
}
/// @relates expected
template <class T, class Enum, uint8_t = error_category<Enum>::value>
bool operator==(const expected<T>& x, Enum y) {
template <class T, class Enum>
std::enable_if_t<is_error_code_enum_v<Enum>, bool>
operator==(const expected<T>& x, Enum y) {
return x == make_error(y);
}
/// @relates expected
template <class Enum, class T, uint8_t = error_category<Enum>::value>
bool operator==(Enum x, const expected<T>& y) {
template <class T, class Enum>
std::enable_if_t<is_error_code_enum_v<Enum>, bool>
operator==(Enum x, const expected<T>& y) {
return y == make_error(x);
}
......@@ -341,14 +343,16 @@ bool operator!=(const error& x, const expected<T>& y) {
}
/// @relates expected
template <class T, class Enum, uint8_t = error_category<Enum>::value>
bool operator!=(const expected<T>& x, Enum y) {
template <class T, class Enum>
std::enable_if_t<is_error_code_enum_v<Enum>, bool>
operator!=(const expected<T>& x, Enum y) {
return !(x == y);
}
/// @relates expected
template <class T, class Enum, uint8_t = error_category<Enum>::value>
bool operator!=(Enum x, const expected<T>& y) {
template <class T, class Enum>
std::enable_if_t<is_error_code_enum_v<Enum>, bool>
operator!=(Enum x, const expected<T>& y) {
return !(x == y);
}
......@@ -375,7 +379,7 @@ public:
// nop
}
template <class Enum, uint8_t = error_category<Enum>::value>
template <class Enum, class = std::enable_if_t<is_error_code_enum_v<Enum>>>
expected(Enum code) : error_(code) {
// nop
}
......
......@@ -181,10 +181,11 @@ config_option make_config_option(T& storage, string_view category,
// -- enums --------------------------------------------------------------------
enum class byte : uint8_t;
enum class exit_reason : uint8_t;
enum class invoke_message_result;
enum class pec : uint8_t;
enum class sec : uint8_t;
enum class stream_priority;
enum class invoke_message_result;
// -- aliases ------------------------------------------------------------------
......
......@@ -18,13 +18,17 @@
#pragma once
#include <cstdint>
namespace caf {
/// Customization point for enabling conversion from an enum type to an
/// @ref error.
/// @ref error or @ref error_code.
template <class T>
struct is_error_code_enum {
static constexpr bool value = false;
};
/// @relates is_error_code_enum
template <class T>
struct error_category;
constexpr bool is_error_code_enum_v = is_error_code_enum<T>::value;
} // namespace caf
// Deprecated include. The next CAF release won't include this header.
......@@ -22,8 +22,8 @@
#include <string>
#include "caf/detail/core_export.hpp"
#include "caf/error_category.hpp"
#include "caf/fwd.hpp"
#include "caf/is_error_code_enum.hpp"
namespace caf {
......@@ -80,8 +80,8 @@ enum class pec : uint8_t {
CAF_CORE_EXPORT std::string to_string(pec);
template <>
struct error_category<pec> {
static constexpr uint8_t value = 1;
struct is_error_code_enum<pec> {
static constexpr bool value = true;
};
} // namespace caf
......@@ -62,7 +62,7 @@ public:
result_base& operator=(const result_base&) = default;
template <class Enum, uint8_t = error_category<Enum>::value>
template <class Enum, class = std::enable_if_t<is_error_code_enum_v<Enum>>>
result_base(Enum x) : content_(make_error(x)) {
// nop
}
......
......@@ -26,8 +26,8 @@
#include <string>
#include "caf/detail/core_export.hpp"
#include "caf/error_category.hpp"
#include "caf/fwd.hpp"
#include "caf/is_error_code_enum.hpp"
namespace caf {
......@@ -147,11 +147,12 @@ enum class sec : uint8_t {
all_requests_failed,
};
/// @relates sec
CAF_CORE_EXPORT std::string to_string(sec);
template <>
struct error_category<sec> {
static constexpr uint8_t value = 0;
struct is_error_code_enum<sec> {
static constexpr bool value = true;
};
} // namespace caf
......@@ -24,6 +24,7 @@
#include <utility>
#include "caf/detail/core_export.hpp"
#include "caf/detail/is_complete.hpp"
#include "caf/detail/pp.hpp"
#include "caf/detail/squashed_int.hpp"
#include "caf/fwd.hpp"
......@@ -83,6 +84,10 @@ constexpr const char* type_name_v = type_name<T>::value;
/// The first type ID not reserved by CAF and its modules.
constexpr type_id_t first_custom_type_id = 200;
/// Checks whether `type_id` is specialized for `T`.
template <class T>
constexpr bool has_type_id = detail::is_complete<type_id<T>>;
} // namespace caf
/// Starts a code block for registering custom types to CAF. Stores the first ID
......@@ -243,6 +248,7 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
CAF_ADD_TYPE_ID(core_module, (caf::downstream_msg))
CAF_ADD_TYPE_ID(core_module, (caf::error))
CAF_ADD_TYPE_ID(core_module, (caf::exit_msg))
CAF_ADD_TYPE_ID(core_module, (caf::exit_reason))
CAF_ADD_TYPE_ID(core_module, (caf::group))
CAF_ADD_TYPE_ID(core_module, (caf::group_down_msg))
CAF_ADD_TYPE_ID(core_module, (caf::message))
......@@ -250,6 +256,8 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
CAF_ADD_TYPE_ID(core_module, (caf::node_down_msg))
CAF_ADD_TYPE_ID(core_module, (caf::node_id))
CAF_ADD_TYPE_ID(core_module, (caf::open_stream_msg))
CAF_ADD_TYPE_ID(core_module, (caf::pec))
CAF_ADD_TYPE_ID(core_module, (caf::sec))
CAF_ADD_TYPE_ID(core_module, (caf::strong_actor_ptr))
CAF_ADD_TYPE_ID(core_module, (caf::timeout_msg))
CAF_ADD_TYPE_ID(core_module, (caf::timespan))
......
......@@ -364,12 +364,6 @@ actor_registry& actor_system::registry() {
}
std::string actor_system::render(const error& x) const {
if (!x)
return to_string(x);
auto& xs = config().error_renderers;
auto i = xs.find(x.category());
if (i != xs.end())
return i->second(x.code(), x.context());
return to_string(x);
}
......
......@@ -136,10 +136,6 @@ actor_system_config::actor_system_config()
"path to an OpenSSL-style directory of trusted certificates")
.add<string>(openssl_cafile, "cafile",
"path to a file of concatenated PEM-formatted certificates");
// add renderers for default error categories
add_error_category(error_category<sec>::value, render_sec);
add_error_category(error_category<pec>::value, render_pec);
add_error_category(error_category<exit_reason>::value, render_exit_reason);
}
settings actor_system_config::dump_content() const {
......@@ -358,14 +354,8 @@ actor_system_config& actor_system_config::add_actor_factory(std::string name,
return *this;
}
actor_system_config& actor_system_config::add_error_category(uint8_t x,
error_renderer y) {
error_renderers[x] = y;
return *this;
}
actor_system_config&
actor_system_config::set_impl(string_view name, config_value value) {
actor_system_config& actor_system_config::set_impl(string_view name,
config_value value) {
if (name == "middleman.app-identifier") {
// TODO: Print a warning with 0.18 and remove this code with 0.19.
value.convert_to_list();
......@@ -393,39 +383,9 @@ timespan actor_system_config::stream_tick_duration() const noexcept {
stream_max_batch_delay.count());
return timespan{ns_count};
}
std::string actor_system_config::render(const error& x) {
if (!x)
return "none";
switch (x.category()) {
case error_category<sec>::value:
return render_sec(x.code(), x.context());
case error_category<exit_reason>::value:
return render_exit_reason(x.code(), x.context());
case error_category<pec>::value:
return render_pec(x.code(), x.context());
default:
return deep_to_string(meta::type_name("error"), x.code(), x.category(),
meta::omittable_if_empty(), x.context());
}
}
std::string actor_system_config::render_sec(uint8_t x, const message& xs) {
auto tmp = static_cast<sec>(x);
return deep_to_string(meta::type_name("system_error"), tmp,
meta::omittable_if_empty(), xs);
}
std::string actor_system_config::render_exit_reason(uint8_t x,
const message& xs) {
auto tmp = static_cast<exit_reason>(x);
return deep_to_string(meta::type_name("exit_reason"), tmp,
meta::omittable_if_empty(), xs);
}
std::string actor_system_config::render_pec(uint8_t x, const message& xs) {
auto tmp = static_cast<pec>(x);
return deep_to_string(meta::type_name("parser_error"), tmp,
meta::omittable_if_empty(), xs);
std::string actor_system_config::render(const error& x) {
return to_string(x);
}
expected<settings>
......
......@@ -157,7 +157,7 @@ auto config_option_set::parse(settings& config, argument_iterator first,
auto val = opt.parse(slice);
if (!val) {
auto& err = val.error();
if (err.category() == error_category<pec>::value)
if (err.category() == type_id_v<pec>)
return static_cast<pec>(err.code());
return pec::invalid_argument;
}
......
......@@ -22,155 +22,70 @@
#include "caf/config.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/deserializer.hpp"
#include "caf/detail/meta_object.hpp"
#include "caf/message.hpp"
#include "caf/serializer.hpp"
namespace caf {
// -- nested classes -----------------------------------------------------------
struct error::data {
uint8_t code;
uint8_t category;
message context;
};
// -- constructors, destructors, and assignment operators ----------------------
error::error() noexcept : data_(nullptr) {
// nop
}
error::error(none_t) noexcept : data_(nullptr) {
// nop
}
error::error(error&& x) noexcept : data_(x.data_) {
if (data_ != nullptr)
x.data_ = nullptr;
}
error& error::operator=(error&& x) noexcept {
if (this != &x)
std::swap(data_, x.data_);
return *this;
}
error::error(const error& x) : data_(x ? new data(*x.data_) : nullptr) {
// nop
}
error& error::operator=(const error& x) {
if (this == &x)
return *this;
if (x) {
if (data_ == nullptr)
data_ = new data(*x.data_);
data_.reset(new data(*x.data_));
else
*data_ = *x.data_;
} else {
clear();
data_.reset();
}
return *this;
}
error::error(uint8_t x, uint8_t y)
: data_(x != 0 ? new data{x, y, message{}} : nullptr) {
error::error(uint8_t code, type_id_t category)
: error(code, category, message{}) {
// nop
}
error::error(uint8_t x, uint8_t y, message z)
: data_(x != 0 ? new data{x, y, std::move(z)} : nullptr) {
error::error(uint8_t code, type_id_t category, message context)
: data_(code != 0 ? new data{code, category, std::move(context)} : nullptr) {
// nop
}
error::~error() {
delete data_;
}
// -- observers ----------------------------------------------------------------
uint8_t error::code() const noexcept {
CAF_ASSERT(data_ != nullptr);
return data_->code;
}
uint8_t error::category() const noexcept {
CAF_ASSERT(data_ != nullptr);
return data_->category;
}
const message& error::context() const noexcept {
CAF_ASSERT(data_ != nullptr);
return data_->context;
}
int error::compare(const error& x) const noexcept {
uint8_t x_code;
uint8_t x_category;
if (x) {
x_code = x.data_->code;
x_category = x.data_->category;
} else {
x_code = 0;
x_category = 0;
}
return compare(x_code, x_category);
}
int error::compare(uint8_t x, uint8_t y) const noexcept {
uint8_t mx;
uint8_t my;
if (data_ != nullptr) {
mx = data_->code;
my = data_->category;
} else {
mx = 0;
my = 0;
}
// all errors with default value are considered no error -> equal
if (mx == x && x == 0)
return 0;
if (my < y)
return -1;
if (my > y)
return 1;
return static_cast<int>(mx) - x;
}
// -- modifiers --------------------------------------------------------------
message& error::context() noexcept {
CAF_ASSERT(data_ != nullptr);
return data_->context;
return x ? compare(x.data_->code, x.data_->category) : compare(0, 0);
}
void error::clear() noexcept {
if (data_ != nullptr) {
delete data_;
data_ = nullptr;
}
int error::compare(uint8_t code, type_id_t category) const noexcept {
int x = 0;
if (data_ != nullptr)
x = (data_->code << 16) | data_->category;
return x - int{(code << 16) | category};
}
// -- inspection support -----------------------------------------------------
uint8_t& error::code_ref() noexcept {
CAF_ASSERT(data_ != nullptr);
return data_->code;
}
uint8_t& error::category_ref() noexcept {
CAF_ASSERT(data_ != nullptr);
return data_->category;
}
void error::init() {
if (data_ == nullptr)
data_ = new data;
}
std::string to_string(const error& x) {
return actor_system_config::render(x);
if (!x)
return "none";
std::string result;
auto code = x.code();
auto mobj = detail::global_meta_object(x.category());
mobj->stringify(result, &code);
auto ctx = x.context();
if (ctx)
result += to_string(ctx);
return result;
}
} // namespace caf
......@@ -54,11 +54,11 @@ CAF_TEST(serialization roundtrips go through the registry) {
byte_buffer buf;
binary_serializer sink{sys, buf};
if (auto err = sink(hdl))
CAF_FAIL("serialization failed: " << sys.render(err));
CAF_FAIL("serialization failed: " << to_string(err));
actor hdl2;
binary_deserializer source{sys, buf};
if (auto err = source(hdl2))
CAF_FAIL("serialization failed: " << sys.render(err));
CAF_FAIL("serialization failed: " << to_string(err));
CAF_CHECK_EQUAL(hdl, hdl2);
anon_send_exit(hdl, exit_reason::user_shutdown);
}
......
......@@ -71,7 +71,7 @@ struct fixture {
cfg.remainder.clear();
std::istringstream ini{file_content};
if (auto err = cfg.parse(std::move(args), ini))
CAF_FAIL("parse() failed: " << cfg.render(err));
CAF_FAIL("parse() failed: " << err);
}
};
......
......@@ -49,8 +49,7 @@ struct fixture {
auto result = T{};
binary_deserializer source{nullptr, buf};
if (auto err = source(result))
CAF_FAIL("binary_deserializer failed to load: "
<< actor_system_config::render(err));
CAF_FAIL("binary_deserializer failed to load: " << to_string(err));
return result;
}
......@@ -58,8 +57,7 @@ struct fixture {
void load(const std::vector<byte>& buf, Ts&... xs) {
binary_deserializer source{nullptr, buf};
if (auto err = source(xs...))
CAF_FAIL("binary_deserializer failed to load: "
<< actor_system_config::render(err));
CAF_FAIL("binary_deserializer failed to load: " << to_string(err));
}
};
......
......@@ -49,8 +49,7 @@ struct fixture {
byte_buffer result;
binary_serializer sink{nullptr, result};
if (auto err = sink(xs...))
CAF_FAIL("binary_serializer failed to save: "
<< actor_system_config::render(err));
CAF_FAIL("binary_serializer failed to save: " << err);
return result;
}
......@@ -58,8 +57,7 @@ struct fixture {
void save_to_buf(byte_buffer& data, const Ts&... xs) {
binary_serializer sink{nullptr, data};
if (auto err = sink(xs...))
CAF_FAIL("binary_serializer failed to save: "
<< actor_system_config::render(err));
CAF_FAIL("binary_serializer failed to save: " << err);
}
};
......
......@@ -221,7 +221,7 @@ CAF_TEST(adaptor access from actor system config - file input) {
test_config cfg;
std::istringstream in{config_text};
if (auto err = cfg.parse(0, nullptr, in))
CAF_FAIL("cfg.parse failed: " << cfg.render(err));
CAF_FAIL("cfg.parse failed: " << err);
CAF_CHECK_EQUAL(cfg.max_delay, my_duration::from_s(123));
}
......@@ -232,7 +232,7 @@ CAF_TEST(adaptor access from actor system config - file input and arguments) {
test_config cfg;
std::istringstream in{config_text};
if (auto err = cfg.parse(std::move(args), in))
CAF_FAIL("cfg.parse failed: " << cfg.render(err));
CAF_FAIL("cfg.parse failed: " << err);
CAF_CHECK_EQUAL(cfg.max_delay, my_duration::from_ms(20));
}
......
......@@ -24,7 +24,7 @@
#include "caf/all.hpp"
#define ERROR_HANDLER [&](error& err) { CAF_FAIL(system.render(err)); }
#define ERROR_HANDLER [&](error& err) { CAF_FAIL(err); }
using namespace caf;
......
......@@ -345,9 +345,7 @@ CAF_TEST(ranges can use signed integers) {
if (auto res = r(expr)) { \
CAF_FAIL("expected expression to produce to an error"); \
} else { \
auto& err = res.error(); \
CAF_CHECK(err.category() == error_category<pec>::value); \
CAF_CHECK_EQUAL(err.code(), static_cast<uint8_t>(enum_value)); \
CAF_CHECK_EQUAL(res.error(), enum_value); \
}
CAF_TEST(the parser rejects invalid step values) {
......
......@@ -40,7 +40,7 @@ struct fixture : test_coordinator_fixture<> {
byte_buffer buf;
binary_serializer sink{sys, buf};
if (auto err = sink(xs...))
CAF_FAIL("failed to serialize data: " << sys.render(err));
CAF_FAIL("failed to serialize data: " << err);
return buf.size();
}
};
......
......@@ -30,13 +30,13 @@ CAF_TEST(default constructed errors evaluate to false) {
}
CAF_TEST(error code zero is not an error) {
CAF_CHECK(!error(0, error_category<sec>::value));
CAF_CHECK(!error(sec::none));
CAF_CHECK(!make_error(sec::none));
CAF_CHECK(!error{error_code<sec>(sec::none)});
}
CAF_TEST(error codes that are not zero are errors) {
CAF_CHECK(error(1, error_category<sec>::value));
CAF_CHECK(error(sec::unexpected_message));
CAF_CHECK(make_error(sec::unexpected_message));
CAF_CHECK(error{error_code<sec>(sec::unexpected_message)});
}
......
......@@ -55,11 +55,11 @@ struct fixture {
byte_buffer buf;
binary_serializer sink(sys, buf);
if (auto err = sink(x))
CAF_FAIL("serialization failed: " << sys.render(err));
CAF_FAIL("serialization failed: " << err);
binary_deserializer source(sys, make_span(buf));
T y;
if (auto err = source(y))
CAF_FAIL("deserialization failed: " << sys.render(err));
CAF_FAIL("deserialization failed: " << err);
return y;
}
};
......
......@@ -55,11 +55,11 @@ struct fixture {
byte_buffer buf;
binary_serializer sink(sys, buf);
if (auto err = sink(x))
CAF_FAIL("serialization failed: " << sys.render(err));
CAF_FAIL("serialization failed: " << err);
binary_deserializer source(sys, make_span(buf));
T y;
if (auto err = source(y))
CAF_FAIL("deserialization failed: " << sys.render(err));
CAF_FAIL("deserialization failed: " << err);
return y;
}
};
......
......@@ -291,7 +291,7 @@ CAF_TEST(object access from actor system config - file input) {
test_config cfg;
std::istringstream in{config_text};
if (auto err = cfg.parse(0, nullptr, in))
CAF_FAIL("cfg.parse failed: " << cfg.render(err));
CAF_FAIL("cfg.parse failed: " << err);
CAF_CHECK_EQUAL(cfg.fb.foo, 42);
CAF_CHECK_EQUAL(cfg.fb.bar, "Don't panic!");
CAF_CHECK_EQUAL(cfg.fbfb.x.foo, 1);
......@@ -308,7 +308,7 @@ CAF_TEST(object access from actor system config - file input and arguments) {
test_config cfg;
std::istringstream in{config_text};
if (auto err = cfg.parse(std::move(args), in))
CAF_FAIL("cfg.parse failed: " << cfg.render(err));
CAF_FAIL("cfg.parse failed: " << err);
CAF_CHECK_EQUAL(cfg.fb.foo, 42);
CAF_CHECK_EQUAL(cfg.fb.bar, "Don't panic!");
CAF_CHECK_EQUAL(cfg.fbfb.x.foo, 10);
......
......@@ -74,7 +74,7 @@ struct fixture : test_coordinator_fixture<> {
} // namespace
#define ERROR_HANDLER [&](error& err) { CAF_FAIL(sys.render(err)); }
#define ERROR_HANDLER [&](error& err) { CAF_FAIL(err); }
#define SUBTEST(message) \
*result = none; \
......
......@@ -22,7 +22,7 @@
#include "caf/all.hpp"
#define ERROR_HANDLER [&](error& err) { CAF_FAIL(system.render(err)); }
#define ERROR_HANDLER [&](error& err) { CAF_FAIL(err); }
using namespace caf;
......
......@@ -46,9 +46,7 @@ struct fixture : test_coordinator_fixture<> {
}
std::function<void(const error&)> make_error_handler() {
return [this](const error& err) {
CAF_FAIL("unexpected error: " << sys.render(err));
};
return [](const error& err) { CAF_FAIL("unexpected error: " << err); };
}
std::function<void(const error&)> make_counting_error_handler(size_t* count) {
......
......@@ -44,9 +44,7 @@ struct fixture : test_coordinator_fixture<> {
}
auto make_error_handler() {
return [this](const error& err) {
CAF_FAIL("unexpected error: " << sys.render(err));
};
return [](const error& err) { CAF_FAIL("unexpected error: " << err); };
}
auto make_counting_error_handler(size_t* count) {
......
......@@ -107,7 +107,7 @@ struct fixture : test_coordinator_fixture<> {
binary_serializer sink{sys, buf};
if (auto err = sink(xs...))
CAF_FAIL("serialization failed: "
<< sys.render(err)
<< err
<< ", data: " << deep_to_string(std::forward_as_tuple(xs...)));
return buf;
}
......@@ -116,7 +116,7 @@ struct fixture : test_coordinator_fixture<> {
void deserialize(const byte_buffer& buf, Ts&... xs) {
binary_deserializer source{sys, buf};
if (auto err = source(xs...))
CAF_FAIL("deserialization failed: " << sys.render(err));
CAF_FAIL("deserialization failed: " << err);
}
// serializes `x` and then deserializes and returns the serialized value
......
......@@ -29,7 +29,7 @@
# include "caf/all.hpp"
# define ERROR_HANDLER [&](error& err) { CAF_FAIL(sys.render(err)); }
# define ERROR_HANDLER [&](error& err) { CAF_FAIL(err); }
using std::string;
......
......@@ -95,12 +95,12 @@ using v20 = variant<i01, i02, i03, i04, i05, i06, i07, i08, i09, i10,
byte_buffer buf; \
binary_serializer sink{sys.dummy_execution_unit(), buf}; \
if (auto err = sink(x3)) \
CAF_FAIL("failed to serialize data: " << sys.render(err)); \
CAF_FAIL("failed to serialize data: " << err); \
CAF_CHECK_EQUAL(x3, i##n{0x##n}); \
v20 tmp; \
binary_deserializer source{sys.dummy_execution_unit(), buf}; \
if (auto err = source(tmp)) \
CAF_FAIL("failed to deserialize data: " << sys.render(err)); \
CAF_FAIL("failed to deserialize data: " << err); \
CAF_CHECK_EQUAL(tmp, i##n{0x##n}); \
CAF_CHECK_EQUAL(tmp, x3); \
}
......
......@@ -28,6 +28,7 @@
#include "caf/meta/load_callback.hpp"
#include "caf/meta/save_callback.hpp"
#include "caf/meta/type_name.hpp"
#include "caf/sec.hpp"
struct sockaddr;
struct sockaddr_storage;
......
......@@ -318,7 +318,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl,
std::set<std::string> sigs;
if (auto err = bd(source_node, app_ids, aid, sigs)) {
CAF_LOG_WARNING("unable to deserialize payload of server handshake:"
<< ctx->system().render(err));
<< to_string(err));
return serializing_basp_payload_failed;
}
// Check the application ID.
......@@ -367,7 +367,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl,
node_id source_node;
if (auto err = bd(source_node)) {
CAF_LOG_WARNING("unable to deserialize payload of client handshake:"
<< ctx->system().render(err));
<< to_string(err));
return serializing_basp_payload_failed;
}
// Drop repeated handshakes.
......@@ -391,7 +391,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl,
if (auto err = bd(source_node, dest_node)) {
CAF_LOG_WARNING(
"unable to deserialize source and destination for routed message:"
<< ctx->system().render(err));
<< to_string(err));
return serializing_basp_payload_failed;
}
if (dest_node != this_node_) {
......@@ -449,7 +449,7 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl,
node_id dest_node;
if (auto err = bd(source_node, dest_node)) {
CAF_LOG_WARNING("unable to deserialize payload of monitor message:"
<< ctx->system().render(err));
<< to_string(err));
return serializing_basp_payload_failed;
}
if (dest_node == this_node_)
......@@ -465,8 +465,8 @@ connection_state instance::handle(execution_unit* ctx, connection_handle hdl,
node_id dest_node;
error fail_state;
if (auto err = bd(source_node, dest_node, fail_state)) {
CAF_LOG_WARNING("unable to deserialize payload of down message:"
<< ctx->system().render(err));
CAF_LOG_WARNING(
"unable to deserialize payload of down message:" << to_string(err));
return serializing_basp_payload_failed;
}
if (dest_node == this_node_) {
......
......@@ -161,7 +161,7 @@ public:
byte_buffer buf;
binary_serializer bs{mpx_, buf};
if (auto err = bs(const_cast<message&>(msg)))
CAF_FAIL("returned to serialize message: " << sys.render(err));
CAF_FAIL("returned to serialize message: " << to_string(err));
return static_cast<uint32_t>(buf.size());
}
......@@ -219,7 +219,7 @@ public:
void to_payload(byte_buffer& buf, const Ts&... xs) {
binary_serializer sink{mpx_, buf};
if (auto err = sink(xs...))
CAF_FAIL("failed to serialize payload: " << sys.render(err));
CAF_FAIL("failed to serialize payload: " << to_string(err));
}
void to_buf(byte_buffer& buf, basp::header& hdr, payload_writer* writer) {
......@@ -347,8 +347,7 @@ public:
{ // lifetime scope of source
binary_deserializer source{this_->mpx(), ob};
if (auto err = source(hdr))
CAF_FAIL("unable to deserialize header: "
<< actor_system_config::render(err));
CAF_FAIL("unable to deserialize header: " << to_string(err));
}
byte_buffer payload;
if (hdr.payload_len > 0) {
......@@ -485,7 +484,7 @@ CAF_TEST(non_empty_server_handshake) {
std::set<std::string> ifs{"caf::replies_to<@u16>::with<@u16>"};
binary_serializer sink{nullptr, expected_payload};
if (auto err = sink(instance().this_node(), app_ids, self()->id(), ifs))
CAF_FAIL("serializing handshake failed: " << sys.render(err));
CAF_FAIL("serializing handshake failed: " << to_string(err));
CAF_CHECK_EQUAL(hexstr(payload), hexstr(expected_payload));
}
......@@ -608,7 +607,7 @@ CAF_TEST(remote_actor_and_send) {
CAF_REQUIRE(proxy == res);
result = actor_cast<actor>(res);
},
[&](error& err) { CAF_FAIL("error: " << sys.render(err)); });
[&](error& err) { CAF_FAIL("error: " << to_string(err)); });
CAF_MESSAGE("send message to proxy");
anon_send(actor_cast<actor>(result), 42);
mpx()->flush_runnables();
......
......@@ -50,7 +50,7 @@ struct fixture : test_coordinator_fixture<> {
byte_buffer buf;
binary_serializer sink{sys, buf};
if (auto err = sink(x, xs...))
CAF_FAIL("serialization failed: " << sys.render(err));
CAF_FAIL("serialization failed: " << to_string(err));
return buf;
}
......@@ -58,7 +58,7 @@ struct fixture : test_coordinator_fixture<> {
void deserialize(const Buffer& buf, T& x, Ts&... xs) {
binary_deserializer source{sys, buf};
if (auto err = source(x, xs...))
CAF_FAIL("serialization failed: " << sys.render(err));
CAF_FAIL("serialization failed: " << to_string(err));
}
};
......
......@@ -109,7 +109,7 @@ CAF_TEST(deliver serialized message) {
std::vector<strong_actor_ptr> stages;
binary_serializer sink{sys, payload};
if (auto err = sink(stages, make_message(ok_atom_v)))
CAF_FAIL("unable to serialize message: " << sys.render(err));
CAF_FAIL("unable to serialize message: " << err);
io::basp::header hdr{io::basp::message_type::direct_message,
0,
static_cast<uint32_t>(payload.size()),
......
......@@ -845,7 +845,7 @@ public:
caf::byte_buffer buf;
caf::binary_serializer sink{sys, buf};
if (auto err = sink(xs...))
CAF_FAIL("serialization failed: " << sys.render(err));
CAF_FAIL("serialization failed: " << err);
return buf;
}
......@@ -853,7 +853,7 @@ public:
void deserialize(const caf::byte_buffer& buf, Ts&... xs) {
caf::binary_deserializer source{sys, buf};
if (auto err = source(xs...))
CAF_FAIL("deserialization failed: " << sys.render(err));
CAF_FAIL("deserialization failed: " << err);
}
template <class T>
......
......@@ -99,7 +99,7 @@ as ``CAF_CHECK`` and provide tests rather than implementing a
},
[&](caf::error& err) {
// Must not happen, stop test.
CAF_FAIL(sys.render(err));
CAF_FAIL(err);
});
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment