// 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 #include #include #include "yarpl/Refcounted.h" #include "yarpl/observable/Subscription.h" namespace yarpl { namespace observable { template class Observer : public yarpl::enable_get_ref { public: // Note: If any of the following methods is overridden in a subclass, the new // methods SHOULD ensure that these are invoked as well. virtual void onSubscribe(std::shared_ptr subscription) { DCHECK(subscription); if (subscription_) { DLOG(ERROR) << "attempt to double subscribe"; subscription->cancel(); return; } if (cancelled_) { subscription->cancel(); } subscription_ = std::move(subscription); } // No further calls to the subscription after this method is invoked. virtual void onComplete() { DCHECK(subscription_) << "Calling onComplete() without a subscription"; subscription_.reset(); } // No further calls to the subscription after this method is invoked. virtual void onError(folly::exception_wrapper) { DCHECK(subscription_) << "Calling onError() without a subscription"; subscription_.reset(); } virtual void onNext(T) = 0; bool isUnsubscribed() const { CHECK(subscription_); return subscription_->isCancelled(); } // Ability to add more subscription objects which will be notified when the // subscription has been cancelled. // Note that calling cancel on the tied subscription is not going to cancel // this subscriber void addSubscription(std::shared_ptr subscription) { if (!subscription_) { subscription->cancel(); return; } subscription_->tieSubscription(std::move(subscription)); } template void addSubscription(OnCancel onCancel) { addSubscription(Subscription::create(std::move(onCancel))); } bool isUnsubscribedOrTerminated() const { return !subscription_ || subscription_->isCancelled(); } protected: void unsubscribe() { if (subscription_) { subscription_->cancel(); } else { cancelled_ = true; } } public: template < typename Next, typename = typename std::enable_if::value>::type> static std::shared_ptr> create(Next next); template < typename Next, typename Error, typename = typename std::enable_if::value>::type, typename = typename std::enable_if< folly::is_invocable::value>::type> static std::shared_ptr> create(Next next, Error error); template < typename Next, typename Error, typename Complete, typename = typename std::enable_if::value>::type, typename = typename std::enable_if< folly::is_invocable::value>::type, typename = typename std::enable_if::value>::type> static std::shared_ptr> create(Next next, Error error, Complete complete); static std::shared_ptr> create() { class NullObserver : public Observer { public: void onNext(T) {} }; return std::make_shared(); } private: std::shared_ptr subscription_; bool cancelled_{false}; }; namespace details { template class Base : public Observer { static_assert(std::is_same, Next>::value, "undecayed"); public: template explicit Base(FNext&& next) : next_(std::forward(next)) {} void onNext(T value) override { next_(std::move(value)); } private: Next next_; }; template class WithError : public Base { static_assert(std::is_same, Error>::value, "undecayed"); public: template WithError(FNext&& next, FError&& error) : Base(std::forward(next)), error_(std::forward(error)) {} void onError(folly::exception_wrapper error) override { error_(std::move(error)); } private: Error error_; }; template class WithErrorAndComplete : public WithError { static_assert( std::is_same, Complete>::value, "undecayed"); public: template WithErrorAndComplete(FNext&& next, FError&& error, FComplete&& complete) : WithError( std::forward(next), std::forward(error)), complete_(std::move(complete)) {} void onComplete() override { complete_(); } private: Complete complete_; }; } // namespace details template template std::shared_ptr> Observer::create(Next next) { return std::make_shared>(std::move(next)); } template template std::shared_ptr> Observer::create(Next next, Error error) { return std::make_shared>( std::move(next), std::move(error)); } template template < typename Next, typename Error, typename Complete, typename, typename, typename> std::shared_ptr> Observer::create(Next next, Error error, Complete complete) { return std::make_shared< details::WithErrorAndComplete>( std::move(next), std::move(error), std::move(complete)); } } // namespace observable } // namespace yarpl