text: // Copyright 2015 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDING_STATE_H_
  #define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDING_STATE_H_
  
  #include <memory>
  #include <string>
  #include <utility>
  
  #include "base/bind.h"
  #include "base/callback.h"
  #include "base/logging.h"
  #include "base/macros.h"
  #include "base/memory/ptr_util.h"
  #include "base/memory/ref_counted.h"
  #include "base/sequenced_task_runner.h"
  #include "base/single_thread_task_runner.h"
  #include "mojo/public/cpp/bindings/bindings_export.h"
  #include "mojo/public/cpp/bindings/connection_error_callback.h"
  #include "mojo/public/cpp/bindings/filter_chain.h"
  #include "mojo/public/cpp/bindings/interface_endpoint_client.h"
  #include "mojo/public/cpp/bindings/interface_id.h"
  #include "mojo/public/cpp/bindings/interface_ptr.h"
  #include "mojo/public/cpp/bindings/interface_ptr_info.h"
  #include "mojo/public/cpp/bindings/interface_request.h"
  #include "mojo/public/cpp/bindings/lib/multiplex_router.h"
  #include "mojo/public/cpp/bindings/message_header_validator.h"
  #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
  #include "mojo/public/cpp/system/core.h"
  
  namespace mojo {
  namespace internal {
  
  class MOJO_CPP_BINDINGS_EXPORT BindingStateBase {
   public:
    BindingStateBase();
    ~BindingStateBase();
  
    void AddFilter(std::unique_ptr<MessageReceiver> filter);
  
    bool HasAssociatedInterfaces() const;
  
    void PauseIncomingMethodCallProcessing();
    void ResumeIncomingMethodCallProcessing();
  
    bool WaitForIncomingMethodCall(
        MojoDeadline deadline = MOJO_DEADLINE_INDEFINITE);
  
    void Close();
    void CloseWithReason(uint32_t custom_reason, const std::string& description);
  
    void RaiseError() { endpoint_client_->RaiseError(); }
  
    void set_connection_error_handler(base::OnceClosure error_handler) {
      DCHECK(is_bound());
      endpoint_client_->set_connection_error_handler(std::move(error_handler));
    }
  
    void set_connection_error_with_reason_handler(
        ConnectionErrorWithReasonCallback error_handler) {
      DCHECK(is_bound());
      endpoint_client_->set_connection_error_with_reason_handler(
          std::move(error_handler));
    }
  
    bool is_bound() const { return !!router_; }
  
    MessagePipeHandle handle() const {
      DCHECK(is_bound());
      return router_->handle();
    }
  
    ReportBadMessageCallback GetBadMessageCallback();
  
    void FlushForTesting();
  
    void EnableTestingMode();
  
    scoped_refptr<internal::MultiplexRouter> RouterForTesting();
  
   protected:
    void BindInternal(ScopedMessagePipeHandle handle,
                      scoped_refptr<base::SingleThreadTaskRunner> runner,
                      const char* interface_name,
                      std::unique_ptr<MessageReceiver> request_validator,
                      bool passes_associated_kinds,
                      bool has_sync_methods,
                      MessageReceiverWithResponderStatus* stub,
                      uint32_t interface_version);
  
    scoped_refptr<internal::MultiplexRouter> router_;
    std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
  
    base::WeakPtrFactory<BindingStateBase> weak_ptr_factory_;
  };
  
  template <typename Interface, typename ImplRefTraits>
  class BindingState : public BindingStateBase {
   public:
    using ImplPointerType = typename ImplRefTraits::PointerType;
  
    explicit BindingState(ImplPointerType impl) {
      stub_.set_sink(std::move(impl));
    }
  
    ~BindingState() { Close(); }
  
    void Bind(ScopedMessagePipeHandle handle,
              scoped_refptr<base::SingleThreadTaskRunner> runner) {
      BindingStateBase::BindInternal(
          std::move(handle), runner, Interface::Name_,
          std::make_unique<typename Interface::RequestValidator_>(),
          Interface::PassesAssociatedKinds_, Interface::HasSyncMethods_, &stub_,
          Interface::Version_);
    }
  
    InterfaceRequest<Interface> Unbind() {
      endpoint_client_.reset();
      InterfaceRequest<Interface> request(router_->PassMessagePipe());
      router_ = nullptr;
      return request;
    }
  
    Interface* impl() { return ImplRefTraits::GetRawPointer(&stub_.sink()); }
    ImplPointerType SwapImplForTesting(ImplPointerType new_impl) {
      Interface* old_impl = impl();
      stub_.set_sink(std::move(new_impl));
      return old_impl;
    }
  
   private:
    typename Interface::template Stub_<ImplRefTraits> stub_;
  
    DISALLOW_COPY_AND_ASSIGN(BindingState);
  };
  
  }  // namesapce internal
  }  // namespace mojo
  
  #endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDING_STATE_H_
  