Rocket.Chat.ReactNative/ios/Pods/Flipper-RSocket/yarpl/single/SingleOperator.h

249 lines
7.5 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/Try.h>
#include <folly/functional/Invoke.h>
#include <utility>
#include "yarpl/single/Single.h"
#include "yarpl/single/SingleObserver.h"
#include "yarpl/single/SingleSubscriptions.h"
namespace yarpl {
namespace single {
/**
* Base (helper) class for operators. Operators are templated on two types:
* D (downstream) and U (upstream). Operators are created by method calls on
* an upstream Single, and are Observables themselves. Multi-stage
* pipelines
* can be built: a Single heading a sequence of Operators.
*/
template <typename U, typename D>
class SingleOperator : public Single<D> {
public:
explicit SingleOperator(std::shared_ptr<Single<U>> upstream)
: upstream_(std::move(upstream)) {}
protected:
///
/// \brief An Operator's subscription.
///
/// When a pipeline chain is active, each Single has a corresponding
/// subscription. Except for the first one, the subscriptions are created
/// against Operators. Each operator subscription has two functions: as a
/// observer for the previous stage; as a subscription for the next one,
/// the user-supplied observer being the last of the pipeline stages.
template <typename Operator>
class Subscription : public ::yarpl::single::SingleSubscription,
public SingleObserver<U>,
public yarpl::enable_get_ref {
protected:
Subscription(
std::shared_ptr<Operator> single,
std::shared_ptr<SingleObserver<D>> observer)
: single_(std::move(single)), observer_(std::move(observer)) {}
~Subscription() {
observer_.reset();
}
void observerOnSuccess(D value) {
terminateImpl(TerminateState::Down(), folly::Try<D>{std::move(value)});
}
void observerOnError(folly::exception_wrapper ew) {
terminateImpl(TerminateState::Down(), folly::Try<D>{std::move(ew)});
}
std::shared_ptr<Operator> getOperator() {
return single_;
}
void terminateErr(folly::exception_wrapper ew) {
terminateImpl(TerminateState::Both(), std::move(ew));
}
// SingleSubscription.
void cancel() override {
terminateImpl(TerminateState::Up(), folly::Try<D>{});
}
// Subscriber.
void onSubscribe(std::shared_ptr<yarpl::single::SingleSubscription>
subscription) override {
upstream_ = std::move(subscription);
observer_->onSubscribe(this->ref_from_this(this));
}
void onError(folly::exception_wrapper ew) override {
terminateImpl(TerminateState::Down(), folly::Try<D>{std::move(ew)});
}
private:
struct TerminateState {
TerminateState(bool u, bool d) : up{u}, down{d} {}
static TerminateState Down() {
return TerminateState{false, true};
}
static TerminateState Up() {
return TerminateState{true, false};
}
static TerminateState Both() {
return TerminateState{true, true};
}
const bool up{false};
const bool down{false};
};
bool isTerminated() const {
return !upstream_ && !observer_;
}
void terminateImpl(TerminateState state, folly::Try<D> maybe) {
if (isTerminated()) {
return;
}
if (auto upstream = std::move(upstream_)) {
if (state.up) {
upstream->cancel();
}
}
if (auto observer = std::move(observer_)) {
if (state.down) {
if (maybe.hasValue()) {
observer->onSuccess(std::move(maybe).value());
} else {
observer->onError(std::move(maybe).exception());
}
}
}
}
/// The Single has the lambda, and other creation parameters.
std::shared_ptr<Operator> single_;
/// This subscription controls the life-cycle of the observer. The
/// observer is retained as long as calls on it can be made. (Note:
/// the observer in turn maintains a reference on this subscription
/// object until cancellation and/or completion.)
std::shared_ptr<SingleObserver<D>> observer_;
/// In an active pipeline, cancel and (possibly modified) request(n)
/// calls should be forwarded upstream. Note that `this` is also a
/// observer for the upstream stage: thus, there are cycles; all of
/// the objects drop their references at cancel/complete.
std::shared_ptr<yarpl::single::SingleSubscription> upstream_;
};
std::shared_ptr<Single<U>> upstream_;
};
template <
typename U,
typename D,
typename F>
class MapOperator : public SingleOperator<U, D> {
using ThisOperatorT = MapOperator<U, D, F>;
using Super = SingleOperator<U, D>;
using OperatorSubscription =
typename Super::template Subscription<ThisOperatorT>;
static_assert(std::is_same<std::decay_t<F>, F>::value, "undecayed");
static_assert(folly::is_invocable_r<D, F, U>::value, "not invocable");
public:
template <typename Func>
MapOperator(std::shared_ptr<Single<U>> upstream, Func&& function)
: Super(std::move(upstream)), function_(std::forward<Func>(function)) {}
void subscribe(std::shared_ptr<SingleObserver<D>> observer) override {
Super::upstream_->subscribe(
// Note: implicit cast to a reference to a observer.
std::make_shared<MapSubscription>(
this->ref_from_this(this), std::move(observer)));
}
private:
class MapSubscription : public OperatorSubscription {
public:
MapSubscription(
std::shared_ptr<ThisOperatorT> single,
std::shared_ptr<SingleObserver<D>> observer)
: OperatorSubscription(std::move(single), std::move(observer)) {}
void onSuccess(U value) override {
try {
auto map_operator = this->getOperator();
this->observerOnSuccess(map_operator->function_(std::move(value)));
} catch (const std::exception& exn) {
folly::exception_wrapper ew{std::current_exception(), exn};
this->observerOnError(std::move(ew));
}
}
};
F function_;
};
template <typename T, typename OnSubscribe>
class FromPublisherOperator : public Single<T> {
static_assert(
std::is_same<std::decay_t<OnSubscribe>, OnSubscribe>::value,
"undecayed");
public:
template <typename F>
explicit FromPublisherOperator(F&& function)
: function_(std::forward<F>(function)) {}
void subscribe(std::shared_ptr<SingleObserver<T>> observer) override {
function_(std::move(observer));
}
private:
OnSubscribe function_;
};
template <typename OnSubscribe>
class SingleVoidFromPublisherOperator : public Single<void> {
static_assert(
std::is_same<std::decay_t<OnSubscribe>, OnSubscribe>::value,
"undecayed");
public:
template <typename F>
explicit SingleVoidFromPublisherOperator(F&& function)
: function_(std::forward<F>(function)) {}
void subscribe(std::shared_ptr<SingleObserverBase<void>> observer) override {
function_(std::move(observer));
}
private:
OnSubscribe function_;
};
} // namespace single
} // namespace yarpl