Rocket.Chat.ReactNative/ios/Pods/Flipper-RSocket/yarpl/observable/Observable.h

561 lines
18 KiB
C++

// Copyright (c) Facebook, Inc. and its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <folly/functional/Invoke.h>
#include <memory>
#include <type_traits>
#include <utility>
#include "yarpl/Refcounted.h"
#include "yarpl/observable/Observer.h"
#include "yarpl/observable/Subscription.h"
#include "yarpl/Common.h"
#include "yarpl/Flowable.h"
#include "yarpl/flowable/Flowable_FromObservable.h"
namespace yarpl {
namespace observable {
template <typename T = void>
class Observable : public yarpl::enable_get_ref {
public:
static std::shared_ptr<Observable<T>> empty() {
auto lambda = [](std::shared_ptr<Observer<T>> observer) {
observer->onComplete();
};
return Observable<T>::create(std::move(lambda));
}
static std::shared_ptr<Observable<T>> error(folly::exception_wrapper ex) {
auto lambda =
[ex = std::move(ex)](std::shared_ptr<Observer<T>> observer) mutable {
observer->onError(std::move(ex));
};
return Observable<T>::create(std::move(lambda));
}
template <typename Ex>
static std::shared_ptr<Observable<T>> error(Ex&) {
static_assert(
std::is_lvalue_reference<Ex>::value,
"use variant of error() method accepting also exception_ptr");
}
template <typename Ex>
static std::shared_ptr<Observable<T>> error(Ex& ex, std::exception_ptr ptr) {
auto lambda = [ew = folly::exception_wrapper(std::move(ptr), ex)](
std::shared_ptr<Observer<T>> observer) mutable {
observer->onError(std::move(ew));
};
return Observable<T>::create(std::move(lambda));
}
static std::shared_ptr<Observable<T>> just(T value) {
auto lambda =
[value = std::move(value)](std::shared_ptr<Observer<T>> observer) {
observer->onNext(value);
observer->onComplete();
};
return Observable<T>::create(std::move(lambda));
}
/**
* The Defer operator waits until an observer subscribes to it, and then it
* generates an Observable with an ObservableFactory function. It
* does this afresh for each subscriber, so although each subscriber may
* think it is subscribing to the same Observable, in fact each subscriber
* gets its own individual sequence.
*/
template <
typename ObservableFactory,
typename = typename std::enable_if<folly::is_invocable_r<
std::shared_ptr<Observable<T>>,
std::decay_t<ObservableFactory>&>::value>::type>
static std::shared_ptr<Observable<T>> defer(ObservableFactory&&);
static std::shared_ptr<Observable<T>> justN(std::initializer_list<T> list) {
auto lambda = [v = std::vector<T>(std::move(list))](
std::shared_ptr<Observer<T>> observer) {
for (auto const& elem : v) {
observer->onNext(elem);
}
observer->onComplete();
};
return Observable<T>::create(std::move(lambda));
}
// this will generate an observable which can be subscribed to only once
static std::shared_ptr<Observable<T>> justOnce(T value) {
auto lambda = [value = std::move(value), used = false](
std::shared_ptr<Observer<T>> observer) mutable {
if (used) {
observer->onError(
std::runtime_error("justOnce value was already used"));
return;
}
used = true;
observer->onNext(std::move(value));
observer->onComplete();
};
return Observable<T>::create(std::move(lambda));
}
template <typename OnSubscribe>
static std::shared_ptr<Observable<T>> create(OnSubscribe&&);
template <typename OnSubscribe>
static std::shared_ptr<Observable<T>> createEx(OnSubscribe&&);
virtual std::shared_ptr<Subscription> subscribe(
std::shared_ptr<Observer<T>>) = 0;
/**
* Subscribe overload that accepts lambdas.
*/
template <
typename Next,
typename = typename std::enable_if<
folly::is_invocable<std::decay_t<Next>&, T>::value>::type>
std::shared_ptr<Subscription> subscribe(Next&& next) {
return subscribe(Observer<T>::create(std::forward<Next>(next)));
}
/**
* Subscribe overload that accepts lambdas.
*/
template <
typename Next,
typename Error,
typename = typename std::enable_if<
folly::is_invocable<std::decay_t<Next>&, T>::value &&
folly::is_invocable<std::decay_t<Error>&, folly::exception_wrapper>::
value>::type>
std::shared_ptr<Subscription> subscribe(Next&& next, Error&& error) {
return subscribe(Observer<T>::create(
std::forward<Next>(next), std::forward<Error>(error)));
}
/**
* Subscribe overload that accepts lambdas.
*/
template <
typename Next,
typename Error,
typename Complete,
typename = typename std::enable_if<
folly::is_invocable<std::decay_t<Next>&, T>::value &&
folly::is_invocable<std::decay_t<Error>&, folly::exception_wrapper>::
value &&
folly::is_invocable<std::decay_t<Complete>&>::value>::type>
std::shared_ptr<Subscription>
subscribe(Next&& next, Error&& error, Complete&& complete) {
return subscribe(Observer<T>::create(
std::forward<Next>(next),
std::forward<Error>(error),
std::forward<Complete>(complete)));
}
std::shared_ptr<Subscription> subscribe() {
return subscribe(Observer<T>::create());
}
template <
typename Function,
typename R = typename folly::invoke_result_t<Function, T>>
std::shared_ptr<Observable<R>> map(Function&& function);
template <typename Function>
std::shared_ptr<Observable<T>> filter(Function&& function);
template <
typename Function,
typename R = typename folly::invoke_result_t<Function, T, T>>
std::shared_ptr<Observable<R>> reduce(Function&& function);
std::shared_ptr<Observable<T>> take(int64_t);
std::shared_ptr<Observable<T>> skip(int64_t);
std::shared_ptr<Observable<T>> ignoreElements();
std::shared_ptr<Observable<T>> subscribeOn(folly::Executor&);
std::shared_ptr<Observable<T>> concatWith(std::shared_ptr<Observable<T>>);
template <typename... Args>
std::shared_ptr<Observable<T>> concatWith(
std::shared_ptr<Observable<T>> first,
Args... args) {
return concatWith(first)->concatWith(args...);
}
template <typename... Args>
static std::shared_ptr<Observable<T>> concat(
std::shared_ptr<Observable<T>> first,
Args... args) {
return first->concatWith(args...);
}
// function is invoked when onComplete occurs.
template <
typename Function,
typename = typename std::enable_if<
folly::is_invocable<std::decay_t<Function>&>::value>::type>
std::shared_ptr<Observable<T>> doOnSubscribe(Function&& function);
// function is invoked when onNext occurs.
template <
typename Function,
typename = typename std::enable_if<
folly::is_invocable<std::decay_t<Function>&, const T&>::value>::type>
std::shared_ptr<Observable<T>> doOnNext(Function&& function);
// function is invoked when onError occurs.
template <
typename Function,
typename = typename std::enable_if<folly::is_invocable<
std::decay_t<Function>&,
folly::exception_wrapper&>::value>::type>
std::shared_ptr<Observable<T>> doOnError(Function&& function);
// function is invoked when onComplete occurs.
template <
typename Function,
typename = typename std::enable_if<
folly::is_invocable<std::decay_t<Function>&>::value>::type>
std::shared_ptr<Observable<T>> doOnComplete(Function&& function);
// function is invoked when either onComplete or onError occurs.
template <
typename Function,
typename = typename std::enable_if<
folly::is_invocable<std::decay_t<Function>&>::value>::type>
std::shared_ptr<Observable<T>> doOnTerminate(Function&& function);
// the function is invoked for each of onNext, onCompleted, onError
template <
typename Function,
typename = typename std::enable_if<
folly::is_invocable<std::decay_t<Function>&>::value>::type>
std::shared_ptr<Observable<T>> doOnEach(Function&& function);
// the callbacks will be invoked of each of the signals
template <
typename OnNextFunc,
typename OnCompleteFunc,
typename = typename std::enable_if<
folly::is_invocable<std::decay_t<OnNextFunc>&, const T&>::value>::
type,
typename = typename std::enable_if<
folly::is_invocable<std::decay_t<OnCompleteFunc>&>::value>::type>
std::shared_ptr<Observable<T>> doOn(
OnNextFunc&& onNext,
OnCompleteFunc&& onComplete);
// the callbacks will be invoked of each of the signals
template <
typename OnNextFunc,
typename OnCompleteFunc,
typename OnErrorFunc,
typename = typename std::enable_if<
folly::is_invocable<std::decay_t<OnNextFunc>&, const T&>::value>::
type,
typename = typename std::enable_if<
folly::is_invocable<std::decay_t<OnCompleteFunc>&>::value>::type,
typename = typename std::enable_if<folly::is_invocable<
std::decay_t<OnErrorFunc>&,
folly::exception_wrapper&>::value>::type>
std::shared_ptr<Observable<T>>
doOn(OnNextFunc&& onNext, OnCompleteFunc&& onComplete, OnErrorFunc&& onError);
// function is invoked when cancel is called.
template <
typename Function,
typename = typename std::enable_if<
folly::is_invocable<std::decay_t<Function>&>::value>::type>
std::shared_ptr<Observable<T>> doOnCancel(Function&& function);
/**
* Convert from Observable to Flowable with a given BackpressureStrategy.
*/
auto toFlowable(BackpressureStrategy strategy);
/**
* Convert from Observable to Flowable with a given BackpressureStrategy.
*/
auto toFlowable(std::shared_ptr<IBackpressureStrategy<T>> strategy);
};
} // namespace observable
} // namespace yarpl
#include "yarpl/observable/DeferObservable.h"
#include "yarpl/observable/ObservableOperator.h"
namespace yarpl {
namespace observable {
template <typename T>
template <typename OnSubscribe>
std::shared_ptr<Observable<T>> Observable<T>::create(OnSubscribe&& function) {
static_assert(
folly::is_invocable<OnSubscribe&&, std::shared_ptr<Observer<T>>>::value,
"OnSubscribe must have type `void(std::shared_ptr<Observer<T>>)`");
return createEx([func = std::forward<OnSubscribe>(function)](
std::shared_ptr<Observer<T>> observer,
std::shared_ptr<Subscription>) mutable {
func(std::move(observer));
});
}
template <typename T>
template <typename OnSubscribe>
std::shared_ptr<Observable<T>> Observable<T>::createEx(OnSubscribe&& function) {
static_assert(
folly::is_invocable<
OnSubscribe&&,
std::shared_ptr<Observer<T>>,
std::shared_ptr<Subscription>>::value,
"OnSubscribe must have type "
"`void(std::shared_ptr<Observer<T>>, std::shared_ptr<Subscription>)`");
return std::make_shared<FromPublisherOperator<T, std::decay_t<OnSubscribe>>>(
std::forward<OnSubscribe>(function));
}
template <typename T>
template <typename ObservableFactory, typename>
std::shared_ptr<Observable<T>> Observable<T>::defer(
ObservableFactory&& factory) {
return std::make_shared<
details::DeferObservable<T, std::decay_t<ObservableFactory>>>(
std::forward<ObservableFactory>(factory));
}
template <typename T>
template <typename Function, typename R>
std::shared_ptr<Observable<R>> Observable<T>::map(Function&& function) {
return std::make_shared<MapOperator<T, R, std::decay_t<Function>>>(
this->ref_from_this(this), std::forward<Function>(function));
}
template <typename T>
template <typename Function>
std::shared_ptr<Observable<T>> Observable<T>::filter(Function&& function) {
return std::make_shared<FilterOperator<T, std::decay_t<Function>>>(
this->ref_from_this(this), std::forward<Function>(function));
}
template <typename T>
template <typename Function, typename R>
std::shared_ptr<Observable<R>> Observable<T>::reduce(Function&& function) {
return std::make_shared<ReduceOperator<T, R, std::decay_t<Function>>>(
this->ref_from_this(this), std::forward<Function>(function));
}
template <typename T>
std::shared_ptr<Observable<T>> Observable<T>::take(int64_t limit) {
return std::make_shared<TakeOperator<T>>(this->ref_from_this(this), limit);
}
template <typename T>
std::shared_ptr<Observable<T>> Observable<T>::skip(int64_t offset) {
return std::make_shared<SkipOperator<T>>(this->ref_from_this(this), offset);
}
template <typename T>
std::shared_ptr<Observable<T>> Observable<T>::ignoreElements() {
return std::make_shared<IgnoreElementsOperator<T>>(this->ref_from_this(this));
}
template <typename T>
std::shared_ptr<Observable<T>> Observable<T>::subscribeOn(
folly::Executor& executor) {
return std::make_shared<SubscribeOnOperator<T>>(
this->ref_from_this(this), executor);
}
template <typename T>
template <typename Function, typename>
std::shared_ptr<Observable<T>> Observable<T>::doOnSubscribe(
Function&& function) {
return details::createDoOperator(
ref_from_this(this),
std::forward<Function>(function),
[](const T&) {},
[](const auto&) {},
[] {},
[] {}); // onCancel
}
template <typename T>
std::shared_ptr<Observable<T>> Observable<T>::concatWith(
std::shared_ptr<Observable<T>> next) {
return std::make_shared<details::ConcatWithOperator<T>>(
this->ref_from_this(this), std::move(next));
}
template <typename T>
template <typename Function, typename>
std::shared_ptr<Observable<T>> Observable<T>::doOnNext(Function&& function) {
return details::createDoOperator(
ref_from_this(this),
[] {},
std::forward<Function>(function),
[](const auto&) {},
[] {},
[] {}); // onCancel
}
template <typename T>
template <typename Function, typename>
std::shared_ptr<Observable<T>> Observable<T>::doOnError(Function&& function) {
return details::createDoOperator(
ref_from_this(this),
[] {},
[](const T&) {},
std::forward<Function>(function),
[] {},
[] {}); // onCancel
}
template <typename T>
template <typename Function, typename>
std::shared_ptr<Observable<T>> Observable<T>::doOnComplete(
Function&& function) {
return details::createDoOperator(
ref_from_this(this),
[] {},
[](const T&) {},
[](const auto&) {},
std::forward<Function>(function),
[] {}); // onCancel
}
template <typename T>
template <typename Function, typename>
std::shared_ptr<Observable<T>> Observable<T>::doOnTerminate(
Function&& function) {
auto sharedFunction = std::make_shared<std::decay_t<Function>>(
std::forward<Function>(function));
return details::createDoOperator(
ref_from_this(this),
[] {},
[](const T&) {},
[sharedFunction](const auto&) { (*sharedFunction)(); },
[sharedFunction]() { (*sharedFunction)(); },
[] {}); // onCancel
}
template <typename T>
template <typename Function, typename>
std::shared_ptr<Observable<T>> Observable<T>::doOnEach(Function&& function) {
auto sharedFunction = std::make_shared<std::decay_t<Function>>(
std::forward<Function>(function));
return details::createDoOperator(
ref_from_this(this),
[] {},
[sharedFunction](const T&) { (*sharedFunction)(); },
[sharedFunction](const auto&) { (*sharedFunction)(); },
[sharedFunction]() { (*sharedFunction)(); },
[] {}); // onCancel
}
template <typename T>
template <typename OnNextFunc, typename OnCompleteFunc, typename, typename>
std::shared_ptr<Observable<T>> Observable<T>::doOn(
OnNextFunc&& onNext,
OnCompleteFunc&& onComplete) {
return details::createDoOperator(
ref_from_this(this),
[] {},
std::forward<OnNextFunc>(onNext),
[](const auto&) {},
std::forward<OnCompleteFunc>(onComplete),
[] {}); // onCancel
}
template <typename T>
template <
typename OnNextFunc,
typename OnCompleteFunc,
typename OnErrorFunc,
typename,
typename,
typename>
std::shared_ptr<Observable<T>> Observable<T>::doOn(
OnNextFunc&& onNext,
OnCompleteFunc&& onComplete,
OnErrorFunc&& onError) {
return details::createDoOperator(
ref_from_this(this),
[] {},
std::forward<OnNextFunc>(onNext),
std::forward<OnErrorFunc>(onError),
std::forward<OnCompleteFunc>(onComplete),
[] {}); // onCancel
}
template <typename T>
template <typename Function, typename>
std::shared_ptr<Observable<T>> Observable<T>::doOnCancel(Function&& function) {
return details::createDoOperator(
ref_from_this(this),
[] {}, // onSubscribe
[](const auto&) {}, // onNext
[](const auto&) {}, // onError
[] {}, // onComplete
std::forward<Function>(function)); // onCancel
}
template <typename T>
auto Observable<T>::toFlowable(BackpressureStrategy strategy) {
switch (strategy) {
case BackpressureStrategy::DROP:
return toFlowable(IBackpressureStrategy<T>::drop());
case BackpressureStrategy::ERROR:
return toFlowable(IBackpressureStrategy<T>::error());
case BackpressureStrategy::BUFFER:
return toFlowable(IBackpressureStrategy<T>::buffer());
case BackpressureStrategy::LATEST:
return toFlowable(IBackpressureStrategy<T>::latest());
case BackpressureStrategy::MISSING:
return toFlowable(IBackpressureStrategy<T>::missing());
default:
CHECK(false); // unknown value for strategy
}
}
template <typename T>
auto Observable<T>::toFlowable(
std::shared_ptr<IBackpressureStrategy<T>> strategy) {
return yarpl::flowable::internal::flowableFromSubscriber<T>(
[thisObservable = this->ref_from_this(this),
strategy = std::move(strategy)](
std::shared_ptr<flowable::Subscriber<T>> subscriber) {
strategy->init(std::move(thisObservable), std::move(subscriber));
});
}
} // namespace observable
} // namespace yarpl