Docs for PropertyTracker

This commit is contained in:
Simon Hausmann 2021-03-26 10:43:13 +01:00
parent bfd2a2add9
commit 26b58bb0a5

View file

@ -25,37 +25,48 @@ using cbindgen_private::StateInfo;
namespace private_api { namespace private_api {
void sixtyfps_property_set_animated_binding_helper(const cbindgen_private::PropertyHandleOpaque *handle, void sixtyfps_property_set_animated_binding_helper(
void (*binding)(void*, int32_t*), void *user_data, void (*drop_user_data)(void*), const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void *, int32_t *),
void *user_data, void (*drop_user_data)(void *),
const cbindgen_private::PropertyAnimation *animation_data, const cbindgen_private::PropertyAnimation *animation_data,
cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *)) { cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *))
cbindgen_private::sixtyfps_property_set_animated_binding_int(handle, binding, user_data, drop_user_data, animation_data, transition_data); {
cbindgen_private::sixtyfps_property_set_animated_binding_int(
handle, binding, user_data, drop_user_data, animation_data, transition_data);
} }
void sixtyfps_property_set_animated_binding_helper(const cbindgen_private::PropertyHandleOpaque *handle, void sixtyfps_property_set_animated_binding_helper(
void (*binding)(void*, float*), void *user_data, void (*drop_user_data)(void*), const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void *, float *),
void *user_data, void (*drop_user_data)(void *),
const cbindgen_private::PropertyAnimation *animation_data, const cbindgen_private::PropertyAnimation *animation_data,
cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *)) { cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *))
cbindgen_private::sixtyfps_property_set_animated_binding_float(handle, binding, user_data, drop_user_data, animation_data, transition_data); {
cbindgen_private::sixtyfps_property_set_animated_binding_float(
handle, binding, user_data, drop_user_data, animation_data, transition_data);
} }
void sixtyfps_property_set_animated_binding_helper(const cbindgen_private::PropertyHandleOpaque *handle, void sixtyfps_property_set_animated_binding_helper(
void (*binding)(void*, Color*), void *user_data, void (*drop_user_data)(void*), const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void *, Color *),
void *user_data, void (*drop_user_data)(void *),
const cbindgen_private::PropertyAnimation *animation_data, const cbindgen_private::PropertyAnimation *animation_data,
cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *)) { cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *))
cbindgen_private::sixtyfps_property_set_animated_binding_color(handle, binding, user_data, drop_user_data, animation_data, transition_data); {
cbindgen_private::sixtyfps_property_set_animated_binding_color(
handle, binding, user_data, drop_user_data, animation_data, transition_data);
} }
void sixtyfps_property_set_animated_binding_helper(const cbindgen_private::PropertyHandleOpaque *handle, void sixtyfps_property_set_animated_binding_helper(
void (*binding)(void*, Brush*), void *user_data, void (*drop_user_data)(void*), const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void *, Brush *),
void *user_data, void (*drop_user_data)(void *),
const cbindgen_private::PropertyAnimation *animation_data, const cbindgen_private::PropertyAnimation *animation_data,
cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *)) { cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *))
cbindgen_private::sixtyfps_property_set_animated_binding_brush(handle, binding, user_data, drop_user_data, animation_data, transition_data); {
cbindgen_private::sixtyfps_property_set_animated_binding_brush(
handle, binding, user_data, drop_user_data, animation_data, transition_data);
} }
} }
template<typename T> template<typename T>
struct Property struct Property
{ {
@ -103,8 +114,9 @@ struct Property
inline void set_animated_value(const T &value, inline void set_animated_value(const T &value,
const cbindgen_private::PropertyAnimation &animation_data) const; const cbindgen_private::PropertyAnimation &animation_data) const;
template<typename F> template<typename F>
inline void set_animated_binding(F binding, inline void
const cbindgen_private::PropertyAnimation &animation_data) const { set_animated_binding(F binding, const cbindgen_private::PropertyAnimation &animation_data) const
{
private_api::sixtyfps_property_set_animated_binding_helper( private_api::sixtyfps_property_set_animated_binding_helper(
&inner, &inner,
[](void *user_data, T *value) { [](void *user_data, T *value) {
@ -115,19 +127,21 @@ struct Property
} }
template<typename F, typename Trans> template<typename F, typename Trans>
inline void set_animated_binding_for_transition(F binding, Trans animation) const { inline void set_animated_binding_for_transition(F binding, Trans animation) const
struct UserData { {
struct UserData
{
F binding; F binding;
Trans animation; Trans animation;
}; };
private_api::sixtyfps_property_set_animated_binding_helper( private_api::sixtyfps_property_set_animated_binding_helper(
&inner, &inner,
[](void *user_data, T *value) { [](void *user_data, T *value) {
*reinterpret_cast<T *>(value) = reinterpret_cast<UserData *>(user_data)->binding(); *reinterpret_cast<T *>(value) =
reinterpret_cast<UserData *>(user_data)->binding();
}, },
new UserData { binding, animation }, new UserData { binding, animation },
[](void *user_data) { delete reinterpret_cast<UserData *>(user_data); }, [](void *user_data) { delete reinterpret_cast<UserData *>(user_data); }, nullptr,
nullptr,
[](void *user_data, uint64_t *instant) { [](void *user_data, uint64_t *instant) {
return reinterpret_cast<UserData *>(user_data)->animation(instant); return reinterpret_cast<UserData *>(user_data)->animation(instant);
}); });
@ -135,14 +149,16 @@ struct Property
bool is_dirty() const { return cbindgen_private::sixtyfps_property_is_dirty(&inner); } bool is_dirty() const { return cbindgen_private::sixtyfps_property_is_dirty(&inner); }
static void link_two_way(const Property<T> *p1, const Property<T> *p2) { static void link_two_way(const Property<T> *p1, const Property<T> *p2)
{
auto value = p2->get(); auto value = p2->get();
cbindgen_private::PropertyHandleOpaque handle {}; cbindgen_private::PropertyHandleOpaque handle {};
if ((p2->inner._0 & 0b10) == 0b10) { if ((p2->inner._0 & 0b10) == 0b10) {
std::swap(handle, const_cast<Property<T> *>(p2)->inner); std::swap(handle, const_cast<Property<T> *>(p2)->inner);
} }
auto common_property = std::make_shared<Property<T>>(handle, std::move(value)); auto common_property = std::make_shared<Property<T>>(handle, std::move(value));
struct TwoWayBinding { struct TwoWayBinding
{
std::shared_ptr<Property<T>> common_property; std::shared_ptr<Property<T>> common_property;
}; };
auto del_fn = [](void *user_data) { delete reinterpret_cast<TwoWayBinding *>(user_data); }; auto del_fn = [](void *user_data) { delete reinterpret_cast<TwoWayBinding *>(user_data); };
@ -157,24 +173,28 @@ struct Property
}; };
auto intercept_binding_fn = [](void *user_data, void *value) { auto intercept_binding_fn = [](void *user_data, void *value) {
cbindgen_private::sixtyfps_property_set_binding_internal( cbindgen_private::sixtyfps_property_set_binding_internal(
&reinterpret_cast<TwoWayBinding *>(user_data)->common_property->inner, &reinterpret_cast<TwoWayBinding *>(user_data)->common_property->inner, value);
value);
return true; return true;
}; };
cbindgen_private::sixtyfps_property_set_binding(&p1->inner, call_fn, cbindgen_private::sixtyfps_property_set_binding(&p1->inner, call_fn,
new TwoWayBinding{common_property}, del_fn, intercept_fn, intercept_binding_fn); new TwoWayBinding { common_property },
del_fn, intercept_fn, intercept_binding_fn);
cbindgen_private::sixtyfps_property_set_binding(&p2->inner, call_fn, cbindgen_private::sixtyfps_property_set_binding(&p2->inner, call_fn,
new TwoWayBinding{common_property}, del_fn, intercept_fn, intercept_binding_fn); new TwoWayBinding { common_property },
del_fn, intercept_fn, intercept_binding_fn);
} }
/// Internal (private) constructor used by link_two_way /// Internal (private) constructor used by link_two_way
explicit Property(cbindgen_private::PropertyHandleOpaque inner, T value) explicit Property(cbindgen_private::PropertyHandleOpaque inner, T value)
: inner(inner), value(std::move(value)) {} : inner(inner), value(std::move(value))
{
}
private: private:
cbindgen_private::PropertyHandleOpaque inner; cbindgen_private::PropertyHandleOpaque inner;
mutable T value {}; mutable T value {};
template<typename F> friend void set_state_binding(const Property<StateInfo> &property, F binding); template<typename F>
friend void set_state_binding(const Property<StateInfo> &property, F binding);
}; };
template<> template<>
@ -186,32 +206,51 @@ void Property<int32_t>::set_animated_value(
} }
template<> template<>
void Property<float>::set_animated_value(const float &new_value, void Property<float>::set_animated_value(
const cbindgen_private::PropertyAnimation &animation_data) const const float &new_value, const cbindgen_private::PropertyAnimation &animation_data) const
{ {
cbindgen_private::sixtyfps_property_set_animated_value_float(&inner, value, new_value, cbindgen_private::sixtyfps_property_set_animated_value_float(&inner, value, new_value,
&animation_data); &animation_data);
} }
template<typename F> template<typename F>
void set_state_binding(const Property<StateInfo> &property, F binding) { void set_state_binding(const Property<StateInfo> &property, F binding)
{
cbindgen_private::sixtyfps_property_set_state_binding( cbindgen_private::sixtyfps_property_set_state_binding(
&property.inner, &property.inner,
[](void *user_data) -> int32_t { return (*reinterpret_cast<F *>(user_data))(); }, [](void *user_data) -> int32_t { return (*reinterpret_cast<F *>(user_data))(); },
new F(binding), new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); });
[](void *user_data) { delete reinterpret_cast<F *>(user_data); });
} }
/// PropertyTracker allows keeping track of when properties change and lazily evaluate code
/// if necessary.
/// Once constructed, you can call evaluate() with a functor that will be invoked. Any
/// Property<T> types that have their value read from within the invoked functor or any code that's
/// reached from there are added to internal book-keeping. When after returning from evaluate(),
/// any of these accessed properties change their value, the property tracker's is_dirt() function
/// will return true.
///
/// PropertyTracker instances nest, so if during the evaluation of one tracker, another tracker's
/// evaluate() function gets called and properties from within that evaluation change their value
/// later, both tracker instances will report true for is_dirty(). If you would like to disable the
/// nesting, use the evaluate_as_dependency_root() function instead.
struct PropertyTracker struct PropertyTracker
{ {
/// Constructs a new property tracker instance.
PropertyTracker() { cbindgen_private::sixtyfps_property_tracker_init(&inner); } PropertyTracker() { cbindgen_private::sixtyfps_property_tracker_init(&inner); }
/// Destroys the property tracker.
~PropertyTracker() { cbindgen_private::sixtyfps_property_tracker_drop(&inner); } ~PropertyTracker() { cbindgen_private::sixtyfps_property_tracker_drop(&inner); }
/// The copy constructor is intentionally deleted, property trackers cannot be copied.
PropertyTracker(const PropertyTracker &) = delete; PropertyTracker(const PropertyTracker &) = delete;
/// The assignment operator is intentionally deleted, property trackers cannot be copied.
PropertyTracker &operator=(const PropertyTracker &) = delete; PropertyTracker &operator=(const PropertyTracker &) = delete;
/// Returns true if any properties accessed during the last evaluate() call have changed their
/// value since then.
bool is_dirty() const { return cbindgen_private::sixtyfps_property_tracker_is_dirty(&inner); } bool is_dirty() const { return cbindgen_private::sixtyfps_property_tracker_is_dirty(&inner); }
/// Invokes the provided functor \a f and tracks accessed to any properties during that
/// invokation.
template<typename F> template<typename F>
auto evaluate(const F &f) const -> std::enable_if_t<std::is_same_v<decltype(f()), void>> auto evaluate(const F &f) const -> std::enable_if_t<std::is_same_v<decltype(f()), void>>
{ {
@ -219,6 +258,9 @@ struct PropertyTracker
&inner, [](void *f) { (*reinterpret_cast<const F *>(f))(); }, const_cast<F *>(&f)); &inner, [](void *f) { (*reinterpret_cast<const F *>(f))(); }, const_cast<F *>(&f));
} }
/// Invokes the provided functor \a f and tracks accessed to any properties during that
/// invokation. Use this overload if your functor returns a value, as evaluate() will pass it on
/// and return it.
template<typename F> template<typename F>
auto evaluate(const F &f) const auto evaluate(const F &f) const
-> std::enable_if_t<!std::is_same_v<decltype(f()), void>, decltype(f())> -> std::enable_if_t<!std::is_same_v<decltype(f()), void>, decltype(f())>
@ -228,13 +270,25 @@ struct PropertyTracker
return result; return result;
} }
/// Invokes the provided functor \a f and tracks accessed to any properties during that
/// invokation.
///
/// This starts a new dependency chain and if called during the evaluation of another
/// property tracker, the outer tracker will not be notified if any accessed properties change.
template<typename F> template<typename F>
auto evaluate_as_dependency_root(const F &f) const -> std::enable_if_t<std::is_same_v<decltype(f()), void>> auto evaluate_as_dependency_root(const F &f) const
-> std::enable_if_t<std::is_same_v<decltype(f()), void>>
{ {
cbindgen_private::sixtyfps_property_tracker_evaluate_as_dependency_root( cbindgen_private::sixtyfps_property_tracker_evaluate_as_dependency_root(
&inner, [](void *f) { (*reinterpret_cast<const F *>(f))(); }, const_cast<F *>(&f)); &inner, [](void *f) { (*reinterpret_cast<const F *>(f))(); }, const_cast<F *>(&f));
} }
/// Invokes the provided functor \a f and tracks accessed to any properties during that
/// invokation. Use this overload if your functor returns a value, as evaluate() will pass it on
/// and return it.
///
/// This starts a new dependency chain and if called during the evaluation of another
/// property tracker, the outer tracker will not be notified if any accessed properties change.
template<typename F> template<typename F>
auto evaluate_as_dependency_root(const F &f) const auto evaluate_as_dependency_root(const F &f) const
-> std::enable_if_t<!std::is_same_v<decltype(f()), void>, decltype(f())> -> std::enable_if_t<!std::is_same_v<decltype(f()), void>, decltype(f())>
@ -249,4 +303,3 @@ private:
}; };
} // namespace sixtyfps } // namespace sixtyfps