Unverified Commit d893c05d authored by Joseph Noir's avatar Joseph Noir Committed by GitHub

Merge pull request #1100

Use type IDs for error code enums
parents bb2f6ae5 0ba1ca56
......@@ -42,6 +42,14 @@ is based on [Keep a Changelog](https://keepachangelog.com).
losing connection to the monitored node.
- In preparation of potential future API additions/changes, CAF now includes an
RFC4122-compliant `uuid` class.
- The new trait class `is_error_code_enum` allows users to enable conversion of
custom error code enums to `error` and `error_code`.
### Deprecated
- The `to_string` output for `error` now renders the error code enum by default.
This renders the member functions `actor_system::render` and
`actor_system_config::render` obsolete.
### Changed
......
......@@ -30,8 +30,7 @@ using kickoff_atom = atom_constant<atom("kickoff")>;
// utility function to print an exit message with custom name
void print_on_exit(scheduled_actor* self, const std::string& name) {
self->attach_functor([=](const error& reason) {
aout(self) << name << " exited: " << self->home_system().render(reason)
<< endl;
aout(self) << name << " exited: " << to_string(reason) << endl;
});
}
......@@ -174,8 +173,8 @@ void run_server(actor_system& system, const config& cfg) {
auto server_actor = system.middleman().spawn_server(server, cfg.port,
pong_actor);
if (!server_actor)
cerr << "unable to spawn server: "
<< system.render(server_actor.error()) << endl;
cerr << "unable to spawn server: " << to_string(server_actor.error())
<< endl;
}
void run_client(actor_system& system, const config& cfg) {
......@@ -184,8 +183,8 @@ void run_client(actor_system& system, const config& cfg) {
auto io_actor = system.middleman().spawn_client(protobuf_io, cfg.host,
cfg.port, ping_actor);
if (!io_actor) {
cout << "cannot connect to " << cfg.host << " at port " << cfg.port
<< ": " << system.render(io_actor.error()) << endl;
cout << "cannot connect to " << cfg.host << " at port " << cfg.port << ": "
<< to_string(io_actor.error()) << endl;
return;
}
send_as(*io_actor, ping_actor, kickoff_atom::value, *io_actor);
......
......@@ -192,8 +192,8 @@ void run_server(actor_system& system, const config& cfg) {
auto server_actor = system.middleman().spawn_server(server, cfg.port,
pong_actor);
if (!server_actor) {
std::cerr << "failed to spawn server: "
<< system.render(server_actor.error()) << endl;
std::cerr << "failed to spawn server: " << to_string(server_actor.error())
<< endl;
return;
}
print_on_exit(*server_actor, "server");
......@@ -205,7 +205,7 @@ void run_client(actor_system& system, const config& cfg) {
auto io_actor = system.middleman().spawn_client(broker_impl, cfg.host,
cfg.port, ping_actor);
if (!io_actor) {
std::cerr << "failed to spawn client: " << system.render(io_actor.error())
std::cerr << "failed to spawn client: " << to_string(io_actor.error())
<< endl;
return;
}
......
......@@ -77,8 +77,8 @@ public:
void caf_main(actor_system& system, const config& cfg) {
auto server_actor = system.middleman().spawn_server(server, cfg.port);
if (!server_actor) {
cerr << "*** cannot spawn server: "
<< system.render(server_actor.error()) << endl;
cerr << "*** cannot spawn server: " << to_string(server_actor.error())
<< endl;
return;
}
cout << "*** listening on port " << cfg.port << endl;
......
......@@ -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
......
......@@ -37,7 +37,7 @@ void caf_main(actor_system& system) {
: "server\n");
},
[&](error& err) {
aout(self) << "received error " << system.render(err) << " from "
aout(self) << "received error " << to_string(err) << " from "
<< (self->current_sender() == worker ? "worker\n"
: "server\n");
});
......
......@@ -101,8 +101,7 @@ template <class Handle, class... Ts>
void tester(scoped_actor& self, const Handle& hdl, int32_t x, int32_t y,
Ts&&... xs) {
auto handle_err = [&](const error& err) {
aout(self) << "AUT (actor under test) failed: "
<< self->system().render(err) << endl;
aout(self) << "AUT (actor under test) failed: " << to_string(err) << endl;
};
// first test: x + y = z
self->request(hdl, infinite, add_atom_v, x, y)
......
......@@ -27,24 +27,13 @@ std::string to_string(math_error x) {
}
}
namespace caf {
CAF_BEGIN_TYPE_ID_BLOCK(divider, first_custom_type_id)
template <>
struct error_category<math_error> {
static constexpr uint8_t value = 101;
};
CAF_ADD_TYPE_ID(divider, (math_error))
} // namespace caf
CAF_END_TYPE_ID_BLOCK(divider)
class config : public actor_system_config {
public:
config() {
auto renderer = [](uint8_t x, const message&) {
return to_string(static_cast<math_error>(x));
};
add_error_category(caf::error_category<math_error>::value, renderer);
}
};
CAF_ERROR_CODE_ENUM(math_error)
using divider = typed_actor<result<double>(div_atom, double, double)>;
......@@ -58,7 +47,7 @@ divider::behavior_type divider_impl() {
};
}
void caf_main(actor_system& system, const config&) {
void caf_main(actor_system& system) {
double x;
double y;
cout << "x: " << flush;
......@@ -72,8 +61,8 @@ void caf_main(actor_system& system, const config&) {
[&](double z) { aout(self) << x << " / " << y << " = " << z << endl; },
[&](const error& err) {
aout(self) << "*** cannot compute " << x << " / " << y << " => "
<< system.render(err) << endl;
<< to_string(err) << endl;
});
}
CAF_MAIN()
CAF_MAIN(id_block::divider)
......@@ -3,30 +3,25 @@
#include <cstdint>
#include <iostream>
enum class fixed_stack_errc : uint8_t {
push_to_full = 1,
pop_from_empty,
};
CAF_BEGIN_TYPE_ID_BLOCK(fixed_stack, first_custom_type_id)
CAF_ADD_TYPE_ID(fixed_stack, (fixed_stack_errc))
CAF_ADD_ATOM(fixed_stack, pop_atom)
CAF_ADD_ATOM(fixed_stack, push_atom)
CAF_END_TYPE_ID_BLOCK(fixed_stack)
CAF_ERROR_CODE_ENUM(fixed_stack_errc)
using std::endl;
using namespace caf;
enum class fixed_stack_errc : uint8_t {
push_to_full = 1,
pop_from_empty,
};
namespace caf {
template <>
struct error_category<fixed_stack_errc> {
static constexpr uint8_t value = 100;
};
} // namespace caf
class fixed_stack : public event_based_actor {
public:
fixed_stack(actor_config& cfg, size_t stack_size)
......
......@@ -56,8 +56,7 @@ void blocking_testee(blocking_actor* self, vector<cell> cells) {
aout(self) << "cell #" << x.id() << " -> " << y << endl;
},
[&](error& err) {
aout(self) << "cell #" << x.id() << " -> "
<< self->system().render(err) << endl;
aout(self) << "cell #" << x.id() << " -> " << to_string(err) << endl;
});
}
......
......@@ -54,8 +54,8 @@ void tester(event_based_actor* self, const calculator_type& testee) {
});
},
[=](const error& err) {
aout(self) << "AUT (actor under test) failed: "
<< self->system().render(err) << endl;
aout(self) << "AUT (actor under test) failed: " << to_string(err)
<< endl;
self->quit(exit_reason::user_shutdown);
});
}
......
......@@ -79,7 +79,7 @@ void ChatWidget::sendChatMessage() {
auto x = system().groups().get(mod, g);
if (! x)
print("*** error: "
+ QString::fromUtf8(system().render(x.error()).c_str()));
+ QString::fromUtf8(to_string(x.error()).c_str()));
else
self()->send(self(), atom("join"), std::move(*x));
},
......@@ -128,7 +128,7 @@ void ChatWidget::joinGroup() {
string gid = gname.midRef(pos+1).toUtf8().constData();
auto x = system().groups().get(mod, gid);
if (! x)
QMessageBox::critical(this, "Error", system().render(x.error()).c_str());
QMessageBox::critical(this, "Error", to_string(x.error()).c_str());
else
self()->send(self(), join_atom::value, std::move(*x));
}
......
......@@ -59,9 +59,8 @@ int main(int argc, char** argv) {
auto group_uri = cfg.group_id.substr(p + 1);
auto g = system.groups().get(module, group_uri);
if (! g) {
cerr << "*** unable to get group " << group_uri
<< " from module " << module << ": "
<< system.render(g.error()) << endl;
cerr << "*** unable to get group " << group_uri << " from module "
<< module << ": " << to_string(g.error()) << endl;
return -1;
}
grp = std::move(*g);
......
......@@ -145,7 +145,7 @@ void connecting(stateful_actor<state>* self, const std::string& host,
},
[=](const error& err) {
aout(self) << R"(*** cannot connect to ")" << host << R"(":)" << port
<< " => " << self->system().render(err) << endl;
<< " => " << to_string(err) << endl;
self->become(unconnected(self));
});
}
......@@ -286,7 +286,7 @@ void run_server(actor_system& system, const config& cfg) {
cout << "*** try publish at port " << cfg.port << endl;
auto expected_port = io::publish(calc, cfg.port);
if (!expected_port) {
std::cerr << "*** publish failed: " << system.render(expected_port.error())
std::cerr << "*** publish failed: " << to_string(expected_port.error())
<< endl;
return;
}
......
......@@ -85,7 +85,7 @@ void run_server(actor_system& system, const config& cfg) {
auto res = system.middleman().publish_local_groups(cfg.port);
if (!res) {
std::cerr << "*** publishing local groups failed: "
<< system.render(res.error()) << std::endl;
<< to_string(res.error()) << std::endl;
return;
}
std::cout << "*** listening at port " << *res << std::endl
......@@ -112,7 +112,7 @@ void run_client(actor_system& system, const config& cfg) {
anon_send(client_actor, join_atom_v, std::move(*tmp));
else
std::cerr << R"(*** failed to parse ")" << uri << R"(" as group URI: )"
<< system.render(tmp.error()) << std::endl;
<< to_string(tmp.error()) << std::endl;
}
std::istream_iterator<line> eof;
std::vector<std::string> words;
......
......@@ -115,7 +115,7 @@ struct config : actor_system_config {
void server(actor_system& system, const config& cfg) {
auto res = system.middleman().open(cfg.port);
if (!res) {
cerr << "*** cannot open port: " << system.render(res.error()) << endl;
cerr << "*** cannot open port: " << to_string(res.error()) << endl;
return;
}
cout << "*** running on port: " << *res << endl
......@@ -127,7 +127,7 @@ void server(actor_system& system, const config& cfg) {
void client(actor_system& system, const config& cfg) {
auto node = system.middleman().connect(cfg.host, cfg.port);
if (!node) {
cerr << "*** connect failed: " << system.render(node.error()) << endl;
cerr << "*** connect failed: " << to_string(node.error()) << endl;
return;
}
auto type = "calculator"; // type of the actor we wish to spawn
......@@ -136,8 +136,7 @@ void client(actor_system& system, const config& cfg) {
auto worker = system.middleman().remote_spawn<calculator>(*node, type, args,
tout);
if (!worker) {
cerr << "*** remote spawn failed: " << system.render(worker.error())
<< endl;
cerr << "*** remote spawn failed: " << to_string(worker.error()) << endl;
return;
}
// start using worker in main loop
......
......@@ -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.
......@@ -5,7 +5,7 @@
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* 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 *
......@@ -18,13 +18,19 @@
#pragma once
#include <cstdint>
#include <type_traits>
namespace caf {
namespace caf::detail {
/// Customization point for enabling conversion from an enum type to an
/// @ref error.
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>
struct error_category;
constexpr bool is_complete
= decltype(is_complete_impl(std::declval<T*>()))::value;
} // namespace caf
} // 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 {
......@@ -60,46 +61,39 @@ namespace caf {
///
/// # Why is there no `string()` member function?
///
/// The C++ standard library uses category singletons and virtual dispatching
/// to correlate error codes to descriptive strings. However, singletons are
/// a poor choice when it comes to serialization. CAF uses atoms for
/// categories instead and requires users to register custom error categories
/// to the actor system. This makes the actor system the natural instance for
/// rendering error messages via `actor_system::render(const error&)`.
/// The C++ standard library uses category singletons and virtual dispatching to
/// correlate error codes to descriptive strings. However, singletons are a poor
/// choice when it comes to serialization. CAF uses type IDs and meta objects
/// instead.
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 +109,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 +141,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 +174,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 +214,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 +236,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 +262,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 = std::underlying_type_t<Enum>;
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
......@@ -63,6 +68,10 @@ public:
return value_;
}
friend constexpr underlying_type to_integer(error_code x) noexcept {
return static_cast<std::underlying_type_t<Enum>>(x.value());
}
private:
enum_type 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 {
......@@ -52,12 +52,9 @@ enum class exit_reason : uint8_t {
unreachable
};
/// Returns a string representation of given exit reason.
/// @relates exit_reason
CAF_CORE_EXPORT std::string to_string(exit_reason);
template <>
struct error_category<exit_reason> {
static constexpr uint8_t value = 3;
};
} // namespace caf
CAF_ERROR_CODE_ENUM(exit_reason)
......@@ -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 ------------------------------------------------------------------
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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
namespace caf {
/// Customization point for enabling conversion from an enum type to an
/// @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>
constexpr bool is_error_code_enum_v = is_error_code_enum<T>::value;
} // namespace caf
#define CAF_ERROR_CODE_ENUM(type_name) \
namespace caf { \
template <> \
struct is_error_code_enum<type_name> { \
static constexpr bool value = true; \
}; \
}
// 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 {
......@@ -79,9 +79,6 @@ enum class pec : uint8_t {
CAF_CORE_EXPORT std::string to_string(pec);
template <>
struct error_category<pec> {
static constexpr uint8_t value = 1;
};
} // namespace caf
CAF_ERROR_CODE_ENUM(pec)
......@@ -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,9 @@ 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;
};
} // namespace caf
CAF_ERROR_CODE_ENUM(sec)
......@@ -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: " << 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: " << 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) {
......
......@@ -71,8 +71,6 @@ CAF_TEST(test_serial_reply) {
CAF_MESSAGE("ID of main: " << self->id());
self->request(master, infinite, hi_atom::value)
.receive([](ho_atom) { CAF_MESSAGE("received 'ho'"); },
[&](const error& err) {
CAF_ERROR("Error: " << self->system().render(err));
});
[&](const error& err) { CAF_ERROR("Error: " << to_string(err)); });
CAF_REQUIRE(self->mailbox().empty());
}
......@@ -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: " << 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: " << 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: " << 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: " << 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: " << 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: " << 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: " << 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()),
......
......@@ -646,9 +646,7 @@ struct test_coordinator_fixture_fetch_helper {
operator()(caf::response_handle<Self, Policy<Interface>>& from) const {
std::tuple<Ts...> result;
from.receive([&](Ts&... xs) { result = std::make_tuple(std::move(xs)...); },
[&](caf::error& err) {
FAIL(from.self()->system().render(err));
});
[&](caf::error& err) { CAF_FAIL(err); });
return result;
}
};
......@@ -659,9 +657,7 @@ struct test_coordinator_fixture_fetch_helper<T> {
T operator()(caf::response_handle<Self, Policy<Interface>>& from) const {
T result;
from.receive([&](T& x) { result = std::move(x); },
[&](caf::error& err) {
FAIL(from.self()->system().render(err));
});
[&](caf::error& err) { CAF_FAIL(err); });
return result;
}
};
......@@ -845,7 +841,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 +849,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>
......
......@@ -274,8 +274,8 @@ construction arguments passed as message can mismatch, this version of
auto x = system.spawn<calculator>("calculator", make_message());
if (! x) {
std::cerr << "*** unable to spawn calculator: "
<< system.render(x.error()) << std::endl;
std::cerr << "*** unable to spawn calculator: " << to_string(x.error())
<< std::endl;
return;
}
calculator c = std::move(*x);
......
......@@ -14,8 +14,8 @@ name, joining, and leaving.
std::string id = "foo";
auto expected_grp = system.groups().get(module, id);
if (! expected_grp) {
std::cerr << "*** cannot load group: "
<< system.render(expected_grp.error()) << std::endl;
std::cerr << "*** cannot load group: " << to_string(expected_grp.error())
<< std::endl;
return;
}
auto grp = std::move(*expected_grp);
......
......@@ -92,12 +92,10 @@ connect to the published actor by calling ``remote_actor``:
// node B
auto ping = system.middleman().remote_actor("node A", 4242);
if (! ping) {
cerr << "unable to connect to node A: "
<< system.render(ping.error()) << std::endl;
} else {
if (!ping)
cerr << "unable to connect to node A: " << to_string(ping.error()) << '\n';
else
self->send(*ping, ping_atom::value);
}
There is no difference between server and client after the connection phase.
Remote actors use the same handle types as local actors and are thus fully
......
......@@ -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);
});
}
......
......@@ -161,8 +161,8 @@ void bootstrap(actor_system& system, const string& wdir,
// possible addresses slaves can use to connect to us
auto port_res = system.middleman().publish(self, 0);
if (!port_res) {
cerr << "fatal: unable to publish actor: "
<< system.render(port_res.error()) << endl;
cerr << "fatal: unable to publish actor: " << to_string(port_res.error())
<< endl;
return;
}
auto port = *port_res;
......
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