Commit c9586ff1 authored by Dominik Charousset's avatar Dominik Charousset Committed by Dominik Charousset

Make sure message IDs match their content

parent 7fec52d0
......@@ -65,14 +65,6 @@ public:
~mailbox_element() override;
type_erased_tuple& content() override;
message move_content_to_message() override;
message copy_content_to_message() const override;
const type_erased_tuple& content() const;
inline bool is_high_priority() const {
return mid.category() == message_id::urgent_message_category;
}
......@@ -81,9 +73,37 @@ public:
mailbox_element(const mailbox_element&) = delete;
mailbox_element& operator=(mailbox_element&&) = delete;
mailbox_element& operator=(const mailbox_element&) = delete;
};
protected:
empty_type_erased_tuple dummy_;
/// Corrects the message ID for down- and upstream messages to make sure the
/// category for a `mailbox_element` matches its content.
template <class...>
struct mailbox_category_corrector {
static constexpr message_id apply(message_id x) {
return x;
}
};
template <>
struct mailbox_category_corrector<downstream_msg> {
static message_id apply(message_id x) {
// Downstream messages are always asynchronous. (TODO: true?)
CAF_ASSERT(x.is_async());
CAF_IGNORE_UNUSED(x);
return make_message_id(message_id::downstream_message_category
<< message_id::category_offset);
}
};
template <>
struct mailbox_category_corrector<upstream_msg> {
static message_id apply(message_id x) {
// Upstream messages are always asynchronous. (TODO: true?)
CAF_ASSERT(x.is_async());
CAF_IGNORE_UNUSED(x);
return make_message_id(message_id::upstream_message_category
<< message_id::category_offset);
}
};
/// @relates mailbox_element
......@@ -95,15 +115,18 @@ typename Inspector::result_type inspect(Inspector& f, mailbox_element& x) {
/// Encapsulates arbitrary data in a message element.
template <class... Ts>
class mailbox_element_vals
class mailbox_element_vals final
: public mailbox_element,
public detail::tuple_vals_impl<type_erased_tuple, Ts...> {
public:
template <class... Us>
mailbox_element_vals(strong_actor_ptr&& x0, message_id x1,
forwarding_stack&& x2, Us&&... xs)
: mailbox_element(std::move(x0), x1, std::move(x2)),
detail::tuple_vals_impl<type_erased_tuple, Ts...>(std::forward<Us>(xs)...) {
: mailbox_element(std::move(x0),
mailbox_category_corrector<Ts...>::apply(x1),
std::move(x2)),
detail::tuple_vals_impl<type_erased_tuple, Ts...>(
std::forward<Us>(xs)...) {
// nop
}
......@@ -130,13 +153,16 @@ public:
/// Provides a view for treating arbitrary data as message element.
template <class... Ts>
class mailbox_element_view : public mailbox_element,
public detail::type_erased_tuple_view<Ts...> {
class mailbox_element_view final
: public mailbox_element,
public detail::type_erased_tuple_view<Ts...> {
public:
mailbox_element_view(strong_actor_ptr&& x0, message_id x1,
forwarding_stack&& x2, Ts&... xs)
: mailbox_element(std::move(x0), x1, std::move(x2)),
detail::type_erased_tuple_view<Ts...>(xs...) {
: mailbox_element(std::move(x0),
mailbox_category_corrector<Ts...>::apply(x1),
std::move(x2)),
detail::type_erased_tuple_view<Ts...>(xs...) {
// nop
}
......
......@@ -18,25 +18,39 @@
#include "caf/mailbox_element.hpp"
#include "caf/message_builder.hpp"
#include "caf/type_nr.hpp"
namespace caf {
namespace {
message_id dynamic_category_correction(const message& msg, message_id mid) {
auto tt = msg.type_token();
if (tt == make_type_token<downstream_msg>())
return mailbox_category_corrector<downstream_msg>::apply(mid);
if (tt == make_type_token<upstream_msg>())
return mailbox_category_corrector<upstream_msg>::apply(mid);
return mid;
}
/// Wraps a `message` into a mailbox element.
class mailbox_element_wrapper : public mailbox_element {
class mailbox_element_wrapper final : public mailbox_element {
public:
mailbox_element_wrapper(strong_actor_ptr&& x0, message_id x1,
forwarding_stack&& x2, message&& x3)
: mailbox_element(std::move(x0), x1, std::move(x2)),
: mailbox_element(std::move(x0), dynamic_category_correction(x3, x1),
std::move(x2)),
msg_(std::move(x3)) {
// nop
/// Make sure that `content` can access the raw pointer safely.
if (msg_.vals().raw_ptr() == nullptr) {
message_builder mb;
msg_ = mb.to_message();
}
}
type_erased_tuple& content() override {
auto ptr = msg_.vals().raw_ptr();
if (ptr != nullptr)
return *ptr;
return dummy_;
return *msg_.vals().raw_ptr();
}
message move_content_to_message() override {
......@@ -70,22 +84,6 @@ mailbox_element::~mailbox_element() {
// nop
}
type_erased_tuple& mailbox_element::content() {
return dummy_;
}
message mailbox_element::move_content_to_message() {
return {};
}
message mailbox_element::copy_content_to_message() const {
return {};
}
const type_erased_tuple& mailbox_element::content() const {
return const_cast<mailbox_element*>(this)->content();
}
mailbox_element_ptr
make_mailbox_element(strong_actor_ptr sender, message_id id,
mailbox_element::forwarding_stack stages, message msg) {
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2017 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* 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. *
******************************************************************************/
#define CAF_SUITE mailbox_element
#include <string>
#include <tuple>
#include <vector>
#include "caf/all.hpp"
#include "caf/test/unit_test.hpp"
using std::make_tuple;
using std::string;
using std::tuple;
using std::vector;
using namespace caf;
namespace {
template <class... Ts>
optional<tuple<Ts...>> fetch(type_erased_tuple& x) {
if (!x.match_elements<Ts...>())
return none;
return x.get_as_tuple<Ts...>();
}
template <class... Ts>
optional<tuple<Ts...>> fetch(message& x) {
return fetch<Ts...>(x.content());
}
template <class... Ts>
optional<tuple<Ts...>> fetch(mailbox_element& x) {
return fetch<Ts...>(x.content());
}
} // namespace <anonymous>
CAF_TEST(empty_message) {
auto m1 = make_mailbox_element(nullptr, make_message_id(),
no_stages, make_message());
CAF_CHECK(m1->mid.is_async());
CAF_CHECK(m1->mid.category() == message_id::default_message_category);
CAF_CHECK(m1->content().empty());
}
CAF_TEST(non_empty_message) {
auto m1 = make_mailbox_element(nullptr, make_message_id(),
no_stages, make_message(1, 2, 3));
CAF_CHECK(m1->mid.is_async());
CAF_CHECK(m1->mid.category() == message_id::default_message_category);
CAF_CHECK(!m1->content().empty());
CAF_CHECK_EQUAL((fetch<int, int>(*m1)), none);
CAF_CHECK_EQUAL((fetch<int, int, int>(*m1)), make_tuple(1, 2, 3));
}
CAF_TEST(message_roundtrip) {
auto msg = make_message(1, 2, 3);
auto msg_ptr = msg.cvals().get();
auto m1 = make_mailbox_element(nullptr, make_message_id(),
no_stages, std::move(msg));
auto msg2 = m1->move_content_to_message();
CAF_CHECK_EQUAL(msg2.cvals().get(), msg_ptr);
}
CAF_TEST(message_roundtrip_with_copy) {
auto msg = make_message(1, 2, 3);
auto msg_ptr = msg.cvals().get();
auto m1 = make_mailbox_element(nullptr, make_message_id(),
no_stages, std::move(msg));
auto msg2 = m1->copy_content_to_message();
auto msg3 = m1->move_content_to_message();
CAF_CHECK_EQUAL(msg2.cvals().get(), msg_ptr);
CAF_CHECK_EQUAL(msg3.cvals().get(), msg_ptr);
}
CAF_TEST(tuple) {
auto m1 = make_mailbox_element(nullptr, make_message_id(),
no_stages, 1, 2, 3);
CAF_CHECK(m1->mid.is_async());
CAF_CHECK(m1->mid.category() == message_id::default_message_category);
CAF_CHECK(!m1->content().empty());
CAF_CHECK_EQUAL((fetch<int, int>(*m1)), none);
CAF_CHECK_EQUAL((fetch<int, int, int>(*m1)), make_tuple(1, 2, 3));
}
CAF_TEST(move_tuple) {
auto m1 = make_mailbox_element(nullptr, make_message_id(),
no_stages, "hello", "world");
using strings = tuple<string, string>;
CAF_CHECK_EQUAL((fetch<string, string>(*m1)), strings("hello", "world"));
auto msg = m1->move_content_to_message();
CAF_CHECK_EQUAL((fetch<string, string>(msg)), strings("hello", "world"));
CAF_CHECK_EQUAL((fetch<string, string>(*m1)), strings("", ""));
}
CAF_TEST(copy_tuple) {
auto m1 = make_mailbox_element(nullptr, make_message_id(),
no_stages, "hello", "world");
using strings = tuple<string, string>;
CAF_CHECK_EQUAL((fetch<string, string>(*m1)), strings("hello", "world"));
auto msg = m1->copy_content_to_message();
CAF_CHECK_EQUAL((fetch<string, string>(msg)), strings("hello", "world"));
CAF_CHECK_EQUAL((fetch<string, string>(*m1)), strings("hello", "world"));
}
CAF_TEST(high_priority) {
auto m1 = make_mailbox_element(nullptr,
make_message_id(message_priority::high),
no_stages, 42);
CAF_CHECK(m1->mid.category() == message_id::urgent_message_category);
}
CAF_TEST(upstream_msg_static) {
auto m1 = make_mailbox_element(nullptr, make_message_id(), no_stages,
make<upstream_msg::drop>(0, nullptr));
CAF_CHECK(m1->mid.category() == message_id::upstream_message_category);
}
CAF_TEST(upstream_msg_dynamic) {
auto m1 =
make_mailbox_element(nullptr, make_message_id(), no_stages,
make_message(make<upstream_msg::drop>(0, nullptr)));
CAF_CHECK(m1->mid.category() == message_id::upstream_message_category);
}
CAF_TEST(downstream_msg_static) {
auto m1 = make_mailbox_element(nullptr, make_message_id(), no_stages,
make<downstream_msg::close>(0, nullptr));
CAF_CHECK(m1->mid.category() == message_id::downstream_message_category);
}
CAF_TEST(downstream_msg_dynamic) {
auto m1 =
make_mailbox_element(nullptr, make_message_id(), no_stages,
make_message(make<downstream_msg::close>(0, nullptr)));
CAF_CHECK(m1->mid.category() == message_id::downstream_message_category);
}
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