Skip to content

Commit

Permalink
Allow setter nodes to propagate automatically
Browse files Browse the repository at this point in the history
This is a bit dangerous, but it can be useful when we know that the
changes are gonna propagate eventually automatically.  This is sadly
necessay in certain situations when we can not delay the propagation
of the properties due to interactions with animations and so on and so
forth.
  • Loading branch information
arximboldi committed Oct 16, 2020
1 parent ae75bd5 commit ac33a70
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 14 deletions.
4 changes: 2 additions & 2 deletions lager/reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ struct reader_mixin
return with(deriv_()).zoom(std::forward<Lens>(l));
}

template <typename FnT>
template <typename TagT = transactional_tag, typename FnT>
auto setter(FnT&& fn) const
{
return with_setter(deriv_(), std::forward<FnT>(fn));
return with_setter(deriv_(), std::forward<FnT>(fn), TagT{});
}

const DerivT& make() const& { return static_cast<const DerivT&>(*this); }
Expand Down
45 changes: 35 additions & 10 deletions lager/setter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@
#include <lager/detail/nodes.hpp>

#include <lager/cursor.hpp>
#include <lager/tags.hpp>

namespace lager {

namespace detail {

template <typename ParentT, typename FnT>
template <typename ParentT, typename FnT, typename TagT = transactional_tag>
class setter_node : public cursor_node<typename ParentT::value_type>
{
using base_t = cursor_node<typename ParentT::value_type>;

std::shared_ptr<ParentT> parent_;
FnT setter_fn_;
bool recomputed_ = false;

public:
using value_type = typename ParentT::value_type;
Expand All @@ -38,26 +40,43 @@ class setter_node : public cursor_node<typename ParentT::value_type>
, setter_fn_{std::move(fn)}
{}

void recompute() final { this->push_down(parent_->current()); }
void refresh() final { parent_->refresh(); }
void recompute() final
{
if (recomputed_)
recomputed_ = false;
else
this->push_down(parent_->current());
}

void refresh() final {}

void send_up(const value_type& value) override
{
this->push_down(value);
setter_fn_(value);
this->push_down(value);
if constexpr (std::is_same_v<TagT, automatic_tag>) {
recomputed_ = true;
this->send_down();
this->notify();
}
}

void send_up(value_type&& value) override
{
this->push_down(std::move(value));
setter_fn_(value);
this->push_down(std::move(value));
if constexpr (std::is_same_v<TagT, automatic_tag>) {
recomputed_ = true;
this->send_down();
this->notify();
}
}
};

template <typename ParentT, typename FnT>
template <typename TagT = transactional_tag, typename ParentT, typename FnT>
auto make_setter_node(std::shared_ptr<ParentT> p, FnT&& fn)
{
using node_t = setter_node<ParentT, std::decay_t<FnT>>;
using node_t = setter_node<ParentT, std::decay_t<FnT>, TagT>;
auto&& pv = *p;
auto n = std::make_shared<node_t>(std::move(p), std::forward<FnT>(fn));
pv.link(n);
Expand All @@ -66,13 +85,19 @@ auto make_setter_node(std::shared_ptr<ParentT> p, FnT&& fn)

} // namespace detail

template <typename ReaderNode, typename FnT>
template <typename TagT = transactional_tag, typename ReaderNode, typename FnT>
auto with_setter(reader_base<ReaderNode> r, FnT&& fn)
{
auto node = make_setter_node(detail::access::node(std::move(r)),
std::forward<FnT>(fn));
auto node = detail::make_setter_node<TagT>(
detail::access::node(std::move(r)), std::forward<FnT>(fn));
using node_t = typename decltype(node)::element_type;
return cursor_base<node_t>{std::move(node)};
}

template <typename ReaderT, typename FnT, typename TagT = transactional_tag>
auto with_setter(ReaderT&& r, FnT&& fn, TagT = {})
{
return with_setter<TagT>(std::forward<ReaderT>(r), std::forward<FnT>(fn));
}

} // namespace lager
7 changes: 5 additions & 2 deletions lager/with.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <lager/detail/merge_nodes.hpp>
#include <lager/detail/xform_nodes.hpp>

#include <lager/tags.hpp>

#include <zug/transducer/map.hpp>

namespace lager {
Expand Down Expand Up @@ -160,10 +162,11 @@ class with_expr_base
return cursor_t{node};
}

template <typename FnT>
template <typename TagT = transactional_tag, typename FnT>
auto setter(FnT&& fn) &&
{
return std::move(*this).make().setter(std::forward<FnT>(fn));
return std::move(*this).make().template setter<TagT>(
std::forward<FnT>(fn));
}

auto make_node_() &&
Expand Down
27 changes: 27 additions & 0 deletions test/setter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,30 @@ TEST_CASE("combine setter with store")
CHECK(cursor.get() == 5);
CHECK(store.get() == 5);
}

TEST_CASE("combine automatic setter with store")
{
auto store = lager::make_store<int, lager::transactional_tag>(
0, [](int s, int a) { return a; }, lager::with_manual_event_loop{});
auto cursor =
store.xform(zug::identity).setter<lager::automatic_tag>([&](int x) {
store.dispatch(x);
});

CHECK(cursor.get() == 0);

store.dispatch(42);
CHECK(cursor.get() == 0);

lager::commit(store);
CHECK(store.get() == 42);
CHECK(cursor.get() == 42);

cursor.set(5);
CHECK(cursor.get() == 5);
CHECK(store.get() == 42);

lager::commit(store);
CHECK(cursor.get() == 5);
CHECK(store.get() == 5);
}

0 comments on commit ac33a70

Please sign in to comment.