React library wip
This commit is contained in:
parent
cac70befe5
commit
b52039d47c
3 changed files with 123 additions and 30 deletions
|
|
@ -5,42 +5,53 @@
|
|||
namespace psemek::react
|
||||
{
|
||||
|
||||
template <typename F, typename ... Args>
|
||||
auto map(F func, value<Args> ... args)
|
||||
namespace detail
|
||||
{
|
||||
using R = decltype(func(std::declval<Args const &>()...));
|
||||
|
||||
auto node = std::make_shared<detail::node<R>>();
|
||||
auto weak_node = std::weak_ptr{node};
|
||||
template <typename F, typename ... Args>
|
||||
auto map_impl(F func, value<Args> ... args)
|
||||
{
|
||||
using R = decltype(func(std::declval<Args const &>()...));
|
||||
|
||||
auto internal_subscriber = [weak_node]{
|
||||
if (auto node = weak_node.lock())
|
||||
{
|
||||
node->cached_value = std::nullopt;
|
||||
node->internal_signal();
|
||||
}
|
||||
};
|
||||
auto node = std::make_shared<detail::node<R>>();
|
||||
auto weak_node = std::weak_ptr{node};
|
||||
|
||||
auto external_subscriber = [weak_node](auto const &){
|
||||
if (auto node = weak_node.lock())
|
||||
{
|
||||
if (!node->cached_value)
|
||||
node->external_signal(node->value());
|
||||
}
|
||||
};
|
||||
auto internal_subscriber = [weak_node]{
|
||||
if (auto node = weak_node.lock())
|
||||
{
|
||||
node->cached_value = std::nullopt;
|
||||
node->internal_signal();
|
||||
}
|
||||
};
|
||||
|
||||
auto internal_tokens = std::tuple{args.subscribe(detail::internal_tag{}, internal_subscriber)...};
|
||||
auto external_tokens = std::tuple{args.subscribe(external_subscriber)...};
|
||||
auto external_subscriber = [weak_node](auto const &){
|
||||
if (auto node = weak_node.lock())
|
||||
{
|
||||
if (!node->cached_value)
|
||||
node->external_signal(node->value());
|
||||
}
|
||||
};
|
||||
|
||||
node->getter = [
|
||||
func = std::move(func),
|
||||
internal_tokens = std::move(internal_tokens),
|
||||
external_tokens = std::move(external_tokens),
|
||||
args...]() -> R {
|
||||
return func(*args...);
|
||||
};
|
||||
auto internal_tokens = std::tuple{args.subscribe(detail::internal_tag{}, internal_subscriber)...};
|
||||
auto external_tokens = std::tuple{args.subscribe(external_subscriber)...};
|
||||
|
||||
return value<R>(detail::internal_tag{}, std::move(node));
|
||||
node->getter = [
|
||||
func = std::move(func),
|
||||
internal_tokens = std::move(internal_tokens),
|
||||
external_tokens = std::move(external_tokens),
|
||||
args...]() -> R {
|
||||
return func(*args...);
|
||||
};
|
||||
|
||||
return value<R>(detail::internal_tag{}, std::move(node));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <typename F, typename ... Args>
|
||||
auto map(F func, Args && ... args)
|
||||
{
|
||||
return detail::map_impl(std::move(func), make_value(std::forward<Args>(args))...);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,13 @@ namespace psemek::react
|
|||
struct source
|
||||
: value<T>
|
||||
{
|
||||
source(source const &) = default;
|
||||
source(source &&) = default;
|
||||
|
||||
source()
|
||||
: source(T{})
|
||||
{}
|
||||
|
||||
source(T x)
|
||||
: value<T>(detail::internal_tag{}, std::make_shared<detail::node<T>>())
|
||||
{
|
||||
|
|
@ -22,12 +29,41 @@ namespace psemek::react
|
|||
this->node_->internal_signal();
|
||||
this->node_->external_signal(this->node_->value());
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void modify(F && f) const
|
||||
{
|
||||
set(f(this->node_->value()));
|
||||
}
|
||||
|
||||
template <typename H, typename F>
|
||||
source<H> modifier(H value, F && f)
|
||||
{
|
||||
std::weak_ptr weak_node = this->node_;
|
||||
|
||||
source<H> result(std::move(value));
|
||||
this->node_->subscriptions.push_back(result.subscribe([weak_node, f = std::forward<F>(f)](H const & value) mutable {
|
||||
if (auto node = weak_node.lock())
|
||||
{
|
||||
T x = f(node->value(), value);
|
||||
node->cached_value = std::nullopt;
|
||||
node->getter = [x = std::move(x)]() mutable { return std::move(x); };
|
||||
node->internal_signal();
|
||||
node->external_signal(node->value());
|
||||
}
|
||||
}));
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct source<void>
|
||||
: value<void>
|
||||
{
|
||||
source(source const &) = default;
|
||||
source(source &&) = default;
|
||||
|
||||
source()
|
||||
: value<void>(detail::internal_tag{}, std::make_shared<detail::node<void>>())
|
||||
{}
|
||||
|
|
@ -39,4 +75,10 @@ namespace psemek::react
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
value<T> make_value(source<T> const & s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
#include <initializer_list>
|
||||
|
||||
namespace psemek::react
|
||||
{
|
||||
|
|
@ -21,11 +22,12 @@ namespace psemek::react
|
|||
util::signal<T> external_signal;
|
||||
util::function<T()> getter;
|
||||
std::optional<T> cached_value;
|
||||
std::vector<std::shared_ptr<void>> subscriptions;
|
||||
|
||||
T const & value()
|
||||
{
|
||||
if (!cached_value)
|
||||
cached_value = getter();
|
||||
cached_value.emplace(getter());
|
||||
return *cached_value;
|
||||
}
|
||||
};
|
||||
|
|
@ -52,15 +54,41 @@ namespace psemek::react
|
|||
using type = void;
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
constexpr bool is_container = requires { typename C::value_type; };
|
||||
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct value
|
||||
{
|
||||
value() = default;
|
||||
value(value const &) = default;
|
||||
value(value && other) = default;
|
||||
|
||||
template <typename ... Args, typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
|
||||
value(Args && ... args)
|
||||
: node_(std::make_shared<detail::node<T>>())
|
||||
{
|
||||
node_->cached_value.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename C = T, typename = typename C::value_type>
|
||||
value(std::initializer_list<typename C::value_type> list)
|
||||
: node_(std::make_shared<detail::node<T>>())
|
||||
{
|
||||
node_->cached_value.emplace(list);
|
||||
}
|
||||
|
||||
value(detail::internal_tag, std::shared_ptr<detail::node<T>> node)
|
||||
: node_(node)
|
||||
{}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return static_cast<bool>(node_);
|
||||
}
|
||||
|
||||
typename detail::node_value_type<T>::type operator *() const
|
||||
{
|
||||
return node_->value();
|
||||
|
|
@ -87,4 +115,16 @@ namespace psemek::react
|
|||
std::shared_ptr<detail::node<T>> node_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
value<T> make_value(T x)
|
||||
{
|
||||
return value<T>(std::move(x));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
value<T> make_value(value<T> const & v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue