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 @@
#include <folly/experimental/observer/detail/ObserverManager.h>
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 {
template <typename T>
......@@ -34,6 +51,30 @@ template <typename T>
Observer<T>::Observer(observer_detail::Core::Ptr 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>
Observer<observer_detail::ResultOfUnwrapSharedPtr<F>> makeObserver(
F&& creator) {
......@@ -49,9 +90,12 @@ Observer<observer_detail::ResultOfUnwrapSharedPtr<F>> makeObserver(
template <typename F>
Observer<observer_detail::ResultOf<F>> makeObserver(F&& creator) {
return makeObserver([creator = std::forward<F>(creator)]() mutable {
return std::make_shared<observer_detail::ResultOf<F>>(creator());
});
return observer_detail::makeObserver(std::forward<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>
......@@ -132,9 +176,13 @@ Observer<T> makeValueObserver(Observer<T> observer) {
template <typename F>
Observer<observer_detail::ResultOf<F>> makeValueObserver(F&& creator) {
return makeValueObserver([creator = std::forward<F>(creator)]() mutable {
return std::make_shared<observer_detail::ResultOf<F>>(creator());
});
return observer_detail::makeValueObserver(std::forward<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>
......
......@@ -19,6 +19,11 @@
#include <folly/functional/Invoke.h>
namespace folly {
namespace observer {
template <typename T>
class Observer;
}
namespace observer_detail {
template <typename T>
......@@ -29,6 +34,14 @@ struct NonSharedPtr {
template <typename 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>
struct UnwrapSharedPtr {};
......@@ -37,11 +50,28 @@ struct UnwrapSharedPtr<std::shared_ptr<T>> {
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>
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>
using ResultOfUnwrapSharedPtr =
typename UnwrapSharedPtr<invoke_result_t<F>>::type;
template <typename F>
using ResultOfUnwrapObserver =
typename UnwrapObserver<invoke_result_t<F>>::type;
} // namespace observer_detail
} // namespace folly
......@@ -176,6 +176,18 @@ class Observer {
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
* 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);
template <typename F>
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
* skip updates that contain the same (according to operator==) value even if
......
......@@ -70,14 +70,14 @@ struct SimpleObservable<T>::Wrapper {
};
template <typename T>
Observer<T> SimpleObservable<T>::getObserver() {
auto SimpleObservable<T>::getObserver() {
std::call_once(observerInit_, [&]() {
SimpleObservable<T>::Wrapper wrapper;
wrapper.context = context_;
ObserverCreator<SimpleObservable<T>::Wrapper> creator(std::move(wrapper));
observer_ = std::move(creator).getObserver();
});
return *observer_;
return unwrap(*observer_);
}
} // namespace observer
} // namespace folly
......@@ -32,7 +32,7 @@ class SimpleObservable {
void setValue(T value);
void setValue(std::shared_ptr<const T> value);
Observer<T> getObserver();
auto getObserver();
private:
struct Context {
......
......@@ -536,3 +536,35 @@ TEST(Observer, MakeValueObserver) {
EXPECT_EQ(observedValues, 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