Commit 39e09616 authored by Andrii Grynenko's avatar Andrii Grynenko Committed by Facebook GitHub Bot

Unwrap Observer<Observer<T>>>

Differential Revision: D23829791

fbshipit-source-id: 4a13cd70f20de487ece11a1eada94467e1700b6e
parent 0e94731b
...@@ -19,6 +19,23 @@ ...@@ -19,6 +19,23 @@
#include <folly/experimental/observer/detail/ObserverManager.h> #include <folly/experimental/observer/detail/ObserverManager.h>
namespace folly { namespace folly {
namespace observer_detail {
template <typename F>
observer::Observer<ResultOfNoObserverUnwrap<F>> makeObserver(F&& creator) {
return observer::makeObserver([creator = std::forward<F>(creator)]() mutable {
return std::make_shared<ResultOfNoObserverUnwrap<F>>(creator());
});
}
template <typename F>
observer::Observer<ResultOfNoObserverUnwrap<F>> makeValueObserver(F&& creator) {
return observer::makeValueObserver(
[creator = std::forward<F>(creator)]() mutable {
return std::make_shared<ResultOfNoObserverUnwrap<F>>(creator());
});
}
} // namespace observer_detail
namespace observer { namespace observer {
template <typename T> template <typename T>
...@@ -34,6 +51,30 @@ template <typename T> ...@@ -34,6 +51,30 @@ template <typename T>
Observer<T>::Observer(observer_detail::Core::Ptr core) Observer<T>::Observer(observer_detail::Core::Ptr core)
: core_(std::move(core)) {} : core_(std::move(core)) {}
template <typename T>
Observer<T> unwrap(Observer<T> o) {
return o;
}
template <typename T>
Observer<T> unwrapValue(Observer<T> o) {
return makeValueObserver(std::move(o));
}
template <typename T>
Observer<T> unwrap(Observer<Observer<T>> oo) {
return makeObserver([oo = std::move(oo)] {
return oo.getSnapshot()->getSnapshot().getShared();
});
}
template <typename T>
Observer<T> unwrapValue(Observer<Observer<T>> oo) {
return makeValueObserver([oo = std::move(oo)] {
return oo.getSnapshot()->getSnapshot().getShared();
});
}
template <typename F> template <typename F>
Observer<observer_detail::ResultOfUnwrapSharedPtr<F>> makeObserver( Observer<observer_detail::ResultOfUnwrapSharedPtr<F>> makeObserver(
F&& creator) { F&& creator) {
...@@ -49,9 +90,12 @@ Observer<observer_detail::ResultOfUnwrapSharedPtr<F>> makeObserver( ...@@ -49,9 +90,12 @@ Observer<observer_detail::ResultOfUnwrapSharedPtr<F>> makeObserver(
template <typename F> template <typename F>
Observer<observer_detail::ResultOf<F>> makeObserver(F&& creator) { Observer<observer_detail::ResultOf<F>> makeObserver(F&& creator) {
return makeObserver([creator = std::forward<F>(creator)]() mutable { return observer_detail::makeObserver(std::forward<F>(creator));
return std::make_shared<observer_detail::ResultOf<F>>(creator()); }
});
template <typename F>
Observer<observer_detail::ResultOfUnwrapObserver<F>> makeObserver(F&& creator) {
return unwrap(observer_detail::makeObserver(std::forward<F>(creator)));
} }
template <typename T> template <typename T>
...@@ -132,9 +176,13 @@ Observer<T> makeValueObserver(Observer<T> observer) { ...@@ -132,9 +176,13 @@ Observer<T> makeValueObserver(Observer<T> observer) {
template <typename F> template <typename F>
Observer<observer_detail::ResultOf<F>> makeValueObserver(F&& creator) { Observer<observer_detail::ResultOf<F>> makeValueObserver(F&& creator) {
return makeValueObserver([creator = std::forward<F>(creator)]() mutable { return observer_detail::makeValueObserver(std::forward<F>(creator));
return std::make_shared<observer_detail::ResultOf<F>>(creator()); }
});
template <typename F>
Observer<observer_detail::ResultOfUnwrapObserver<F>> makeValueObserver(
F&& creator) {
return unwrapValue(observer_detail::makeObserver(std::forward<F>(creator)));
} }
template <typename F> template <typename F>
......
...@@ -19,6 +19,11 @@ ...@@ -19,6 +19,11 @@
#include <folly/functional/Invoke.h> #include <folly/functional/Invoke.h>
namespace folly { namespace folly {
namespace observer {
template <typename T>
class Observer;
}
namespace observer_detail { namespace observer_detail {
template <typename T> template <typename T>
...@@ -29,6 +34,14 @@ struct NonSharedPtr { ...@@ -29,6 +34,14 @@ struct NonSharedPtr {
template <typename T> template <typename T>
struct NonSharedPtr<std::shared_ptr<T>> {}; struct NonSharedPtr<std::shared_ptr<T>> {};
template <typename T>
struct NonObserver {
using type = typename std::decay<T>::type;
};
template <typename T>
struct NonObserver<observer::Observer<T>> {};
template <typename T> template <typename T>
struct UnwrapSharedPtr {}; struct UnwrapSharedPtr {};
...@@ -37,11 +50,28 @@ struct UnwrapSharedPtr<std::shared_ptr<T>> { ...@@ -37,11 +50,28 @@ struct UnwrapSharedPtr<std::shared_ptr<T>> {
using type = typename std::decay<T>::type; using type = typename std::decay<T>::type;
}; };
template <typename T>
struct UnwrapObserver {};
template <typename T>
struct UnwrapObserver<observer::Observer<T>> {
using type = T;
};
template <typename F> template <typename F>
using ResultOf = typename NonSharedPtr<invoke_result_t<F>>::type; using ResultOf =
typename NonObserver<typename NonSharedPtr<invoke_result_t<F>>::type>::type;
template <typename F>
using ResultOfNoObserverUnwrap =
typename NonSharedPtr<invoke_result_t<F>>::type;
template <typename F> template <typename F>
using ResultOfUnwrapSharedPtr = using ResultOfUnwrapSharedPtr =
typename UnwrapSharedPtr<invoke_result_t<F>>::type; typename UnwrapSharedPtr<invoke_result_t<F>>::type;
template <typename F>
using ResultOfUnwrapObserver =
typename UnwrapObserver<invoke_result_t<F>>::type;
} // namespace observer_detail } // namespace observer_detail
} // namespace folly } // namespace folly
...@@ -176,6 +176,18 @@ class Observer { ...@@ -176,6 +176,18 @@ class Observer {
observer_detail::Core::Ptr core_; observer_detail::Core::Ptr core_;
}; };
template <typename T>
Observer<T> unwrap(Observer<T>);
template <typename T>
Observer<T> unwrapValue(Observer<T>);
template <typename T>
Observer<T> unwrap(Observer<Observer<T>>);
template <typename T>
Observer<T> unwrapValue(Observer<Observer<T>>);
/** /**
* makeObserver(...) creates a new Observer<T> object given a functor to * makeObserver(...) creates a new Observer<T> object given a functor to
* compute it. The functor can return T or std::shared_ptr<const T>. * compute it. The functor can return T or std::shared_ptr<const T>.
...@@ -193,6 +205,9 @@ Observer<observer_detail::ResultOf<F>> makeObserver(F&& creator); ...@@ -193,6 +205,9 @@ Observer<observer_detail::ResultOf<F>> makeObserver(F&& creator);
template <typename F> template <typename F>
Observer<observer_detail::ResultOfUnwrapSharedPtr<F>> makeObserver(F&& creator); Observer<observer_detail::ResultOfUnwrapSharedPtr<F>> makeObserver(F&& creator);
template <typename F>
Observer<observer_detail::ResultOfUnwrapObserver<F>> makeObserver(F&& creator);
/** /**
* The returned Observer will proxy updates from the input observer, but will * The returned Observer will proxy updates from the input observer, but will
* skip updates that contain the same (according to operator==) value even if * skip updates that contain the same (according to operator==) value even if
......
...@@ -70,14 +70,14 @@ struct SimpleObservable<T>::Wrapper { ...@@ -70,14 +70,14 @@ struct SimpleObservable<T>::Wrapper {
}; };
template <typename T> template <typename T>
Observer<T> SimpleObservable<T>::getObserver() { auto SimpleObservable<T>::getObserver() {
std::call_once(observerInit_, [&]() { std::call_once(observerInit_, [&]() {
SimpleObservable<T>::Wrapper wrapper; SimpleObservable<T>::Wrapper wrapper;
wrapper.context = context_; wrapper.context = context_;
ObserverCreator<SimpleObservable<T>::Wrapper> creator(std::move(wrapper)); ObserverCreator<SimpleObservable<T>::Wrapper> creator(std::move(wrapper));
observer_ = std::move(creator).getObserver(); observer_ = std::move(creator).getObserver();
}); });
return *observer_; return unwrap(*observer_);
} }
} // namespace observer } // namespace observer
} // namespace folly } // namespace folly
...@@ -32,7 +32,7 @@ class SimpleObservable { ...@@ -32,7 +32,7 @@ class SimpleObservable {
void setValue(T value); void setValue(T value);
void setValue(std::shared_ptr<const T> value); void setValue(std::shared_ptr<const T> value);
Observer<T> getObserver(); auto getObserver();
private: private:
struct Context { struct Context {
......
...@@ -536,3 +536,35 @@ TEST(Observer, MakeValueObserver) { ...@@ -536,3 +536,35 @@ TEST(Observer, MakeValueObserver) {
EXPECT_EQ(observedValues, std::vector<int>({1, 2, 3})); EXPECT_EQ(observedValues, std::vector<int>({1, 2, 3}));
EXPECT_EQ(observedValues2, std::vector<int>({1, 2, 3})); EXPECT_EQ(observedValues2, std::vector<int>({1, 2, 3}));
} }
TEST(Observer, Unwrap) {
SimpleObservable<bool> selectorObservable{true};
SimpleObservable<int> trueObservable{1};
SimpleObservable<int> falseObservable{2};
auto observer = makeObserver([selectorO = selectorObservable.getObserver(),
trueO = trueObservable.getObserver(),
falseO = falseObservable.getObserver()] {
if (**selectorO) {
return trueO;
}
return falseO;
});
EXPECT_EQ(**observer, 1);
selectorObservable.setValue(false);
folly::observer_detail::ObserverManager::waitForAllUpdates();
EXPECT_EQ(**observer, 2);
falseObservable.setValue(3);
folly::observer_detail::ObserverManager::waitForAllUpdates();
EXPECT_EQ(**observer, 3);
trueObservable.setValue(4);
selectorObservable.setValue(true);
folly::observer_detail::ObserverManager::waitForAllUpdates();
EXPECT_EQ(**observer, 4);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment