Commit 71d2e3e9 authored by Dominik Charousset's avatar Dominik Charousset

Make composition of stream stages type-safe

parent 4c886d32
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "caf/expected.hpp" #include "caf/expected.hpp"
#include "caf/optional.hpp" #include "caf/optional.hpp"
#include "caf/replies_to.hpp" #include "caf/replies_to.hpp"
#include "caf/stream_result.hpp"
#include "caf/detail/implicit_conversions.hpp" #include "caf/detail/implicit_conversions.hpp"
...@@ -51,14 +52,21 @@ struct dmi<result<Ys...> (Xs...)> { ...@@ -51,14 +52,21 @@ struct dmi<result<Ys...> (Xs...)> {
output_tuple<implicit_conversions_t<Ys>...>>; output_tuple<implicit_conversions_t<Ys>...>>;
}; };
// case #2b: function returning a std::tuple<...> // case #2b: function returning a stream_result<...>
template <class Y, class... Xs>
struct dmi<stream_result<Y> (Xs...)> {
using type = typed_mpi<type_list<typename std::decay<Xs>::type...>,
output_tuple<implicit_conversions_t<Y>>>;
};
// case #2c: function returning a std::tuple<...>
template <class... Ys, class... Xs> template <class... Ys, class... Xs>
struct dmi<std::tuple<Ys...> (Xs...)> { struct dmi<std::tuple<Ys...> (Xs...)> {
using type = typed_mpi<type_list<typename std::decay<Xs>::type...>, using type = typed_mpi<type_list<typename std::decay<Xs>::type...>,
output_tuple<implicit_conversions_t<Ys>...>>; output_tuple<implicit_conversions_t<Ys>...>>;
}; };
// case #2c: function returning a std::tuple<...> // case #2d: function returning a std::tuple<...>
template <class... Ys, class... Xs> template <class... Ys, class... Xs>
struct dmi<delegated<Ys...> (Xs...)> { struct dmi<delegated<Ys...> (Xs...)> {
using type = typed_mpi<type_list<typename std::decay<Xs>::type...>, using type = typed_mpi<type_list<typename std::decay<Xs>::type...>,
...@@ -80,6 +88,14 @@ struct dmi<optional<Y> (Xs...)> : dmi<Y (Xs...)> {}; ...@@ -80,6 +88,14 @@ struct dmi<optional<Y> (Xs...)> : dmi<Y (Xs...)> {};
template <class Y, class... Xs> template <class Y, class... Xs>
struct dmi<expected<Y> (Xs...)> : dmi<Y (Xs...)> {}; struct dmi<expected<Y> (Xs...)> : dmi<Y (Xs...)> {};
// case #5: function returning an annotated_stream<>
template <class Y, class... Ys, class... Xs>
struct dmi<annotated_stream<Y, Ys...> (Xs...)> : dmi<Y (Xs...)> {
using type =
typed_mpi<type_list<typename std::decay<Xs>::type...>,
output_tuple<stream<Y>, strip_and_convert_t<Ys>...>>;
};
// -- dmfou = deduce_mpi_function_object_unboxing // -- dmfou = deduce_mpi_function_object_unboxing
template <class T, bool isClass = std::is_class<T>::value> template <class T, bool isClass = std::is_class<T>::value>
......
...@@ -53,6 +53,10 @@ template <class...> class typed_actor_pointer; ...@@ -53,6 +53,10 @@ template <class...> class typed_actor_pointer;
template <class...> class typed_response_promise; template <class...> class typed_response_promise;
template <class...> class typed_event_based_actor; template <class...> class typed_event_based_actor;
// -- variadic templates with 1 fixed argument ---------------------------------
template <class, class...> class annotated_stream;
// -- classes ------------------------------------------------------------------ // -- classes ------------------------------------------------------------------
class actor; class actor;
...@@ -183,6 +187,7 @@ using weak_actor_ptr = weak_intrusive_ptr<actor_control_block>; ...@@ -183,6 +187,7 @@ using weak_actor_ptr = weak_intrusive_ptr<actor_control_block>;
// -- intrusive pointer aliases ------------------------------------------------ // -- intrusive pointer aliases ------------------------------------------------
using stream_handler_ptr = intrusive_ptr<stream_handler>;
using strong_actor_ptr = intrusive_ptr<actor_control_block>; using strong_actor_ptr = intrusive_ptr<actor_control_block>;
// -- unique pointer aliases --------------------------------------------------- // -- unique pointer aliases ---------------------------------------------------
......
This diff is collapsed.
...@@ -20,11 +20,14 @@ ...@@ -20,11 +20,14 @@
#ifndef CAF_STREAM_HPP #ifndef CAF_STREAM_HPP
#define CAF_STREAM_HPP #define CAF_STREAM_HPP
#include "caf/fwd.hpp"
#include "caf/stream_id.hpp" #include "caf/stream_id.hpp"
#include "caf/stream_handler.hpp"
#include "caf/meta/type_name.hpp" #include "caf/meta/type_name.hpp"
namespace caf { namespace caf {
/// Marker type for constructing invalid `stream` objects.
struct invalid_stream_t {}; struct invalid_stream_t {};
/// Identifies an unbound sequence of messages. /// Identifies an unbound sequence of messages.
...@@ -41,14 +44,36 @@ public: ...@@ -41,14 +44,36 @@ public:
// nop // nop
} }
/// Convenience constructor for returning the result of `self->new_stream`
/// and similar functions.
stream(stream_id sid, stream_handler_ptr sptr)
: id_(std::move(sid)),
ptr_(std::move(sptr)) {
// nop
}
/// Convenience constructor for returning the result of `self->new_stream`
/// and similar functions.
stream(stream other, stream_handler_ptr sptr)
: id_(std::move(other.id_)),
ptr_(std::move(sptr)) {
// nop
}
stream(invalid_stream_t) { stream(invalid_stream_t) {
// nop // nop
} }
/// Returns the unique identifier for this stream.
inline const stream_id& id() const { inline const stream_id& id() const {
return id_; return id_;
} }
/// Returns the handler assigned to this stream on this actor.
inline const stream_handler_ptr& ptr() const {
return ptr_;
}
template <class Inspector> template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, stream& x) { friend typename Inspector::result_type inspect(Inspector& f, stream& x) {
return f(meta::type_name("stream"), x.id_); return f(meta::type_name("stream"), x.id_);
...@@ -56,10 +81,24 @@ public: ...@@ -56,10 +81,24 @@ public:
private: private:
stream_id id_; stream_id id_;
stream_handler_ptr ptr_;
}; };
/// @relates stream
constexpr invalid_stream_t invalid_stream = invalid_stream_t{}; constexpr invalid_stream_t invalid_stream = invalid_stream_t{};
/// Identifies an unbound sequence of messages annotated with the additional
/// handshake arguments emitted to the next stage.
template <class T, class... Ts>
class annotated_stream final : public stream<T> {
public:
/// Dennotes the supertype.
using super = stream<T>;
// Import constructors.
using super::super;
};
} // namespace caf } // namespace caf
#endif // CAF_STREAM_HPP #endif // CAF_STREAM_HPP
...@@ -49,6 +49,7 @@ struct stream_msg : tag::boxing_type { ...@@ -49,6 +49,7 @@ struct stream_msg : tag::boxing_type {
/// Identifies content types that propagate errors in both directions. /// Identifies content types that propagate errors in both directions.
flows_both_ways flows_both_ways
}; };
/// Initiates a stream handshake. /// Initiates a stream handshake.
struct open { struct open {
/// Allows visitors to dispatch on this tag. /// Allows visitors to dispatch on this tag.
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* 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. *
******************************************************************************/
#ifndef CAF_STREAM_RESULT_HPP
#define CAF_STREAM_RESULT_HPP
#include "caf/fwd.hpp"
#include "caf/stream_id.hpp"
#include "caf/stream_handler.hpp"
#include "caf/meta/type_name.hpp"
namespace caf {
/// Terminates a stream by reducing it to a single value.
template <class T>
class stream_result {
public:
stream_result() = default;
stream_result(stream_result&&) = default;
stream_result(const stream_result&) = default;
stream_result& operator=(stream_result&&) = default;
stream_result& operator=(const stream_result&) = default;
stream_result(stream_id sid) : id_(std::move(sid)) {
// nop
}
/// Convenience constructor for returning the result of `self->new_stream_result`
/// and similar functions.
stream_result(stream_id sid, stream_handler_ptr sptr)
: id_(std::move(sid)),
ptr_(std::move(sptr)) {
// nop
}
/// Convenience constructor for returning the result of `self->new_stream_result`
/// and similar functions.
stream_result(stream_result other, stream_handler_ptr sptr)
: id_(std::move(other.id_)),
ptr_(std::move(sptr)) {
// nop
}
/// Returns the unique identifier for this stream_result.
inline const stream_id& id() const {
return id_;
}
/// Returns the handler assigned to this stream_result on this actor.
inline const stream_handler_ptr& ptr() const {
return ptr_;
}
template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, stream_result& x) {
return f(meta::type_name("stream_result"), x.id_);
}
private:
stream_id id_;
stream_handler_ptr ptr_;
};
} // namespace caf
#endif // CAF_STREAM_RESULT_HPP
...@@ -379,7 +379,7 @@ scheduled_actor::categorize(mailbox_element& x) { ...@@ -379,7 +379,7 @@ scheduled_actor::categorize(mailbox_element& x) {
return message_category::internal; return message_category::internal;
} }
case make_type_token<stream_msg>(): { case make_type_token<stream_msg>(): {
auto sm = content.move_if_unshared<stream_msg>(0); auto& sm = content.get_mutable_as<stream_msg>(0);
auto e = streams_.end(); auto e = streams_.end();
stream_msg_visitor f{this, sm.sid, streams_.find(sm.sid), e}; stream_msg_visitor f{this, sm.sid, streams_.find(sm.sid), e};
auto res = apply_visitor(f, sm.content); auto res = apply_visitor(f, sm.content);
......
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