|  | // Copyright 2018 The Fuchsia 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 LIB_FIDL_CPP_SYNCHRONOUS_INTERFACE_PTR_H_ | 
|  | #define LIB_FIDL_CPP_SYNCHRONOUS_INTERFACE_PTR_H_ | 
|  |  | 
|  | #include <stddef.h> | 
|  |  | 
|  | #include <memory> | 
|  | #include <utility> | 
|  |  | 
|  | #include "lib/fidl/cpp/interface_handle.h" | 
|  |  | 
|  | namespace fidl { | 
|  |  | 
|  | // A synchronous client interface to a remote implementation of |Interface|. | 
|  | // | 
|  | // An |SynchronousInterfacePtr| implements |Interface| by proxying calls through | 
|  | // a |channel| to a remote implementation of |Interface|. Method calls on the | 
|  | // |Interface| proxy are encoded and sent through the bound channel to the | 
|  | // remote endpoint, which processes them. If the method has a reply (including | 
|  | // any empty reply), the client blocks and waits for the remote endpoint to | 
|  | // reply. | 
|  | // | 
|  | // You need to bind the |SynchronousInterfacePtr| before calling any |Interface| | 
|  | // methods. There are a number of ways to bind the |SynchronousInterfacePtr|. | 
|  | // See |NewRequest|, |Bind|, and the |BindSync| method on |InterfaceHandle|. | 
|  | // | 
|  | // This class is thread-compatible. Once bound, the |SynchronousInterfacePtr| | 
|  | // can be used from multiple threads simultaneously. However, the | 
|  | // |SynchronousInterfacePtr| does not attempt to synchronize mutating operatios, | 
|  | // such as |Bind| or |Unbind|. | 
|  | // | 
|  | // |SynchronousInterfacePtr| does not require a |async_dispatcher_t| | 
|  | // implementation and does not bind to the default |async_dispatcher_t*| for the | 
|  | // current thread, unlike |InterfacePtr|. | 
|  | // | 
|  | // See also: | 
|  | // | 
|  | //  * |Binding|, which is the server analog of an |SynchronousInterfacePtr|. | 
|  | //  * |InterfacePtr|, which is an asynchronous interface to a remote | 
|  | //    implementation. | 
|  | template <typename Interface> | 
|  | class SynchronousInterfacePtr final { | 
|  | public: | 
|  | using InterfaceSync = typename Interface::Sync_; | 
|  |  | 
|  | // Creates an unbound |SynchronousInterfacePtr|. | 
|  | SynchronousInterfacePtr() {} | 
|  | SynchronousInterfacePtr(std::nullptr_t) {} | 
|  |  | 
|  | SynchronousInterfacePtr(const SynchronousInterfacePtr& other) = delete; | 
|  | SynchronousInterfacePtr& operator=(const SynchronousInterfacePtr& other) = delete; | 
|  |  | 
|  | SynchronousInterfacePtr(SynchronousInterfacePtr&& other) = default; | 
|  | SynchronousInterfacePtr& operator=(SynchronousInterfacePtr&& other) = default; | 
|  |  | 
|  | // Bind the |SynchronousInterfacePtr| to one endpoint of a newly created | 
|  | // channel and return the other endpoint as an |InterfaceRequest|. | 
|  | // | 
|  | // Typically, the returned |InterfaceRequest| will be sent to a remote process | 
|  | // to be bound to an implementation of |Interface| using a |Binding| object. | 
|  | // | 
|  | // After calling this method, clients can start calling methods on this | 
|  | // |SynchronousInterfacePtr|. However, methods that have replies will block | 
|  | // until the remote implementation binds the |InterfaceRequest| and replies. | 
|  | // | 
|  | // # Example | 
|  | // | 
|  | // Given the following interface: | 
|  | // | 
|  | //   interface Database { | 
|  | //     OpenTable(request<Table> table); | 
|  | //   }; | 
|  | // | 
|  | // The client can use the |NewRequest| method to create the |InterfaceRequest| | 
|  | // object needed by the |OpenTable| method: | 
|  | // | 
|  | //   DatabasePtr database = ...;  // Connect to database. | 
|  | //   TableSyncPtr table; | 
|  | //   database->OpenTable(table.NewRequest()); | 
|  | // | 
|  | // The client can call methods on |table| immediately. Messages that have | 
|  | // replies will block until the Database implementation binds a Table | 
|  | // implementation and replies. | 
|  | InterfaceRequest<Interface> NewRequest() { | 
|  | zx::channel h1; | 
|  | zx::channel h2; | 
|  | if (zx::channel::create(0, &h1, &h2) != ZX_OK) | 
|  | return nullptr; | 
|  | Bind(std::move(h1)); | 
|  | return InterfaceRequest<Interface>(std::move(h2)); | 
|  | } | 
|  |  | 
|  | // Binds the |SynchronousInterfacePtr| to the given |channel|. | 
|  | // | 
|  | // The |SynchronousInterfacePtr| expects the remote end of the |channel| to | 
|  | // speak the protocol defined by |Interface|. Unlike the |Bind| overload that | 
|  | // takes a |InterfaceHandle| parameter, this |Bind| overload lacks type | 
|  | // safety. | 
|  | // | 
|  | // If the |SynchronousInterfacePtr| was prevously bound to another channel, | 
|  | // that channel is closed. If the |channel| is invalid, then this method will | 
|  | // effectively unbind the |SynchronousInterfacePtr|. A more direct way to have | 
|  | // that effect is to call |Unbind|. | 
|  | // | 
|  | // Does not require the current thread to have a default async_dispatcher_t. | 
|  | void Bind(zx::channel channel) { | 
|  | if (!channel) { | 
|  | proxy_.reset(); | 
|  | return; | 
|  | } | 
|  | proxy_.reset(new typename InterfaceSync::Proxy_(std::move(channel))); | 
|  | } | 
|  |  | 
|  | // Binds the |SynchronousInterfacePtr| to the given |InterfaceHandle|. | 
|  | // | 
|  | // The |SynchronousInterfacePtr| expects the remote end of the |channel| to | 
|  | // speak the protocol defined by |Interface|. Unlike the |Bind| overload that | 
|  | // takes a |channel| parameter, this |Bind| overload provides type safety. | 
|  | // | 
|  | // If the |SynchronousInterfacePtr| was prevously bound to another channel, | 
|  | // that channel is closed. If the |InterfaceHandle| is invalid, then this | 
|  | // method will effectively unbind the |SynchronousInterfacePtr|. A more direct | 
|  | // way to have that effect is to call |Unbind|. | 
|  | // | 
|  | // Does not require the current thread to have a default async_dispatcher_t. | 
|  | void Bind(InterfaceHandle<Interface> handle) { return Bind(handle.TakeChannel()); } | 
|  |  | 
|  | // Unbinds the underlying channel from the |SynchronousInterfacePtr|. | 
|  | // | 
|  | // The underlying channel is returned as an |InterfaceHandle|, which is safe | 
|  | // to transport to another thread or process. | 
|  | // | 
|  | // After this method returns, a subsequent call to |Bind| is required before | 
|  | // calling any additional |Interface| methods. | 
|  | InterfaceHandle<Interface> Unbind() { | 
|  | InterfaceHandle<Interface> handle(proxy_->proxy_.TakeChannel()); | 
|  | proxy_.reset(); | 
|  | return handle; | 
|  | } | 
|  |  | 
|  | // Whether this |SynchronousInterfacePtr| is currently bound to a channel. | 
|  | // | 
|  | // If the |SynchronousInterfacePtr| is bound to a channel, calls to | 
|  | // |Interface| methods are proxied to the remote endpoint of the channel. | 
|  | // | 
|  | // See also: | 
|  | // | 
|  | //  * |Bind|, which binds a channel to this |SynchronousInterfacePtr|. | 
|  | //  * |Unbind|, which unbinds a channel from this |SynchronousInterfacePtr|. | 
|  | bool is_bound() const { return static_cast<bool>(proxy_); } | 
|  |  | 
|  | // Whether this |SynchronousInterfacePtr| is currently bound to a channel. | 
|  | // | 
|  | // See |is_bound| for details. | 
|  | explicit operator bool() const { return is_bound(); } | 
|  |  | 
|  | // The |Interface| proxy associated with this |SynchronousInterfacePtr|. | 
|  | // | 
|  | // When this |SynchronousInterfacePtr| is bound, method calls on this | 
|  | // |Interface| will be proxied to the remote endpoint of the connection. | 
|  | // Methods that expect replies will block until the | 
|  | // |SynchronousInterfacePtr| either receives a reply to that transaction. | 
|  | // | 
|  | // When this |SynchronousInterfacePtr| is not bound, this method returns | 
|  | // nullptr. | 
|  | // | 
|  | // The returned |Interface| is thread-compatible and can be used from any | 
|  | // thread. | 
|  | InterfaceSync* get() const { return proxy_.get(); } | 
|  | InterfaceSync* operator->() const { return get(); } | 
|  | InterfaceSync& operator*() const { return *get(); } | 
|  |  | 
|  | // The underlying channel, or null channel if not currently bound. | 
|  | zx::unowned_channel unowned_channel() const { | 
|  | return proxy_ ? zx::unowned_channel(proxy_->proxy_.channel()) : zx::unowned_channel(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::unique_ptr<typename InterfaceSync::Proxy_> proxy_; | 
|  | }; | 
|  |  | 
|  | }  // namespace fidl | 
|  |  | 
|  | #endif  // LIB_FIDL_CPP_SYNCHRONOUS_INTERFACE_PTR_H_ |