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
|
namespace psemek::react
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename F, typename ... Args>
|
namespace detail
|
||||||
auto map(F func, value<Args> ... args)
|
|
||||||
{
|
{
|
||||||
using R = decltype(func(std::declval<Args const &>()...));
|
|
||||||
|
|
||||||
auto node = std::make_shared<detail::node<R>>();
|
template <typename F, typename ... Args>
|
||||||
auto weak_node = std::weak_ptr{node};
|
auto map_impl(F func, value<Args> ... args)
|
||||||
|
{
|
||||||
|
using R = decltype(func(std::declval<Args const &>()...));
|
||||||
|
|
||||||
auto internal_subscriber = [weak_node]{
|
auto node = std::make_shared<detail::node<R>>();
|
||||||
if (auto node = weak_node.lock())
|
auto weak_node = std::weak_ptr{node};
|
||||||
{
|
|
||||||
node->cached_value = std::nullopt;
|
|
||||||
node->internal_signal();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto external_subscriber = [weak_node](auto const &){
|
auto internal_subscriber = [weak_node]{
|
||||||
if (auto node = weak_node.lock())
|
if (auto node = weak_node.lock())
|
||||||
{
|
{
|
||||||
if (!node->cached_value)
|
node->cached_value = std::nullopt;
|
||||||
node->external_signal(node->value());
|
node->internal_signal();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto internal_tokens = std::tuple{args.subscribe(detail::internal_tag{}, internal_subscriber)...};
|
auto external_subscriber = [weak_node](auto const &){
|
||||||
auto external_tokens = std::tuple{args.subscribe(external_subscriber)...};
|
if (auto node = weak_node.lock())
|
||||||
|
{
|
||||||
|
if (!node->cached_value)
|
||||||
|
node->external_signal(node->value());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
node->getter = [
|
auto internal_tokens = std::tuple{args.subscribe(detail::internal_tag{}, internal_subscriber)...};
|
||||||
func = std::move(func),
|
auto external_tokens = std::tuple{args.subscribe(external_subscriber)...};
|
||||||
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));
|
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
|
struct source
|
||||||
: value<T>
|
: value<T>
|
||||||
{
|
{
|
||||||
|
source(source const &) = default;
|
||||||
|
source(source &&) = default;
|
||||||
|
|
||||||
|
source()
|
||||||
|
: source(T{})
|
||||||
|
{}
|
||||||
|
|
||||||
source(T x)
|
source(T x)
|
||||||
: value<T>(detail::internal_tag{}, std::make_shared<detail::node<T>>())
|
: value<T>(detail::internal_tag{}, std::make_shared<detail::node<T>>())
|
||||||
{
|
{
|
||||||
|
|
@ -22,12 +29,41 @@ namespace psemek::react
|
||||||
this->node_->internal_signal();
|
this->node_->internal_signal();
|
||||||
this->node_->external_signal(this->node_->value());
|
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 <>
|
template <>
|
||||||
struct source<void>
|
struct source<void>
|
||||||
: value<void>
|
: value<void>
|
||||||
{
|
{
|
||||||
|
source(source const &) = default;
|
||||||
|
source(source &&) = default;
|
||||||
|
|
||||||
source()
|
source()
|
||||||
: value<void>(detail::internal_tag{}, std::make_shared<detail::node<void>>())
|
: 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 <optional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
namespace psemek::react
|
namespace psemek::react
|
||||||
{
|
{
|
||||||
|
|
@ -21,11 +22,12 @@ namespace psemek::react
|
||||||
util::signal<T> external_signal;
|
util::signal<T> external_signal;
|
||||||
util::function<T()> getter;
|
util::function<T()> getter;
|
||||||
std::optional<T> cached_value;
|
std::optional<T> cached_value;
|
||||||
|
std::vector<std::shared_ptr<void>> subscriptions;
|
||||||
|
|
||||||
T const & value()
|
T const & value()
|
||||||
{
|
{
|
||||||
if (!cached_value)
|
if (!cached_value)
|
||||||
cached_value = getter();
|
cached_value.emplace(getter());
|
||||||
return *cached_value;
|
return *cached_value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -52,15 +54,41 @@ namespace psemek::react
|
||||||
using type = void;
|
using type = void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename C>
|
||||||
|
constexpr bool is_container = requires { typename C::value_type; };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct value
|
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)
|
value(detail::internal_tag, std::shared_ptr<detail::node<T>> node)
|
||||||
: node_(node)
|
: node_(node)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
explicit operator bool() const
|
||||||
|
{
|
||||||
|
return static_cast<bool>(node_);
|
||||||
|
}
|
||||||
|
|
||||||
typename detail::node_value_type<T>::type operator *() const
|
typename detail::node_value_type<T>::type operator *() const
|
||||||
{
|
{
|
||||||
return node_->value();
|
return node_->value();
|
||||||
|
|
@ -87,4 +115,16 @@ namespace psemek::react
|
||||||
std::shared_ptr<detail::node<T>> node_;
|
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