Skip to content

Commit

Permalink
Make future support optional
Browse files Browse the repository at this point in the history
  • Loading branch information
arximboldi committed Feb 19, 2022
1 parent 8768b5a commit 719e744
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 15 deletions.
10 changes: 10 additions & 0 deletions lager/future.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,16 @@ struct promise
return {promise{state}, future{state}};
}

/*!
* Constructs a promise and future that do not have an associated execution
* context. These are invalid and any function chained in the futures will
* be invoked immediatelly.
*/
static std::pair<promise, future> invalid()
{
return {promise{nullptr}, future{nullptr}};
}

/*!
* Fullfils the promise. Can only be called once for any promise chain!
*/
Expand Down
60 changes: 49 additions & 11 deletions lager/store.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <boost/hana/contains.hpp>
#include <boost/hana/set.hpp>
#include <boost/hana/union.hpp>

#include <memory>
#include <type_traits>
Expand Down Expand Up @@ -128,8 +129,10 @@ class store
reducer_t reducer;
concrete_context_t ctx;

static constexpr bool is_automatic =
boost::hana::contains(Tags{}, boost::hana::type_c<automatic_tag>);
static constexpr bool is_transactional = boost::hana::contains(
Tags{}, boost::hana::type_c<transactional_tag>);
static constexpr bool has_futures = boost::hana::contains(
Tags{}, boost::hana::type_c<enable_futures_tag>);

store_node(model_t init_,
reducer_t reducer_,
Expand All @@ -145,7 +148,12 @@ class store

future dispatch(action_t action) override
{
auto [p, f] = promise::with_loop(loop);
auto [p, f] = [&] {
if constexpr (has_futures)
return promise::with_loop(loop);
else
return promise::invalid();
}();
loop.post([this,
p = std::move(p),
action = std::move(action)]() mutable {
Expand All @@ -157,29 +165,32 @@ class store
loop.post([this,
p = std::move(p),
eff = LAGER_FWD(effect)]() mutable {
if constexpr (is_automatic) {
if constexpr (!is_transactional) {
base_t::send_down();
base_t::notify();
}
if constexpr (std::is_same_v<void,
decltype(eff(ctx))>) {
eff(ctx);
p();
if constexpr (has_futures)
p();
} else {
eff(ctx).then(std::move(p));
auto f = eff(ctx);
if constexpr (has_futures)
std::move(f).then(std::move(p));
}
});
},
[&] {
if constexpr (is_automatic) {
if constexpr (!is_transactional) {
loop.post([this, p = std::move(p)]() mutable {
base_t::send_down();
base_t::notify();
p();
if constexpr (has_futures)
p();
});
} else {
} else if constexpr (has_futures)
p();
}
}));
});
return std::move(f);
Expand All @@ -196,6 +207,33 @@ class store
{}
};

/*!
* Store enhancer that adds certaings tags to the store
*/
template <typename... Tags>
ZUG_INLINE_CONSTEXPR auto with_tags = [](auto next) {
return [next](auto action,
auto&& model,
auto&& reducer,
auto&& loop,
auto&& deps,
auto&& tags) {
return next(action,
LAGER_FWD(model),
LAGER_FWD(reducer),
LAGER_FWD(loop),
LAGER_FWD(deps),
boost::hana::union_(
LAGER_FWD(tags),
boost::hana::make_set(boost::hana::type_c<Tags>...)));
};
};

/*!
* Store enhancer that enables futures support for the given store.
*/
ZUG_INLINE_CONSTEXPR auto with_futures = with_tags<enable_futures_tag>;

/*!
* Store enhancer that adds dependencies to the store.
*
Expand Down Expand Up @@ -313,7 +351,7 @@ ZUG_INLINE_CONSTEXPR struct default_reducer_t
* @endrst
*/
template <typename Action,
typename Tag = automatic_tag,
typename Tag = void, // use default
typename Model,
typename EventLoop,
typename... Enhancers>
Expand Down
2 changes: 2 additions & 0 deletions lager/tags.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@ struct transactional_tag
{};
struct automatic_tag
{};
struct enable_futures_tag
{};

} // namespace lager
13 changes: 9 additions & 4 deletions test/futures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
TEST_CASE("future then callback is called after reducer")
{
auto queue = lager::queue_event_loop{};
auto store = lager::make_store<counter::action>(
counter::model{}, lager::with_queue_event_loop{queue});
auto store =
lager::make_store<counter::action>(counter::model{},
lager::with_queue_event_loop{queue},
lager::with_futures);

auto called = 0;
store.dispatch(counter::increment_action{}).then([&] {
Expand All @@ -43,6 +45,7 @@ TEST_CASE("future then callback is called after effects")
auto store = lager::make_store<int>(
0,
lager::with_queue_event_loop{queue},
lager::with_futures,
lager::with_reducer([&](int s, int a) -> lager::result<int, int> {
if (a == 0)
return {s,
Expand All @@ -66,8 +69,10 @@ TEST_CASE("future then callback is called after effects")
TEST_CASE("combining future")
{
auto queue = lager::queue_event_loop{};
auto store = lager::make_store<counter::action>(
counter::model{}, lager::with_queue_event_loop{queue});
auto store =
lager::make_store<counter::action>(counter::model{},
lager::with_queue_event_loop{queue},
lager::with_futures);

auto called = 0;
store.dispatch(counter::increment_action{})
Expand Down

0 comments on commit 719e744

Please sign in to comment.