1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <fbl/function.h>
8 #include <lib/async/receiver.h>
9 
10 #include <utility>
11 
12 namespace async {
13 
14 // Holds content for a packet receiver and its handler.
15 //
16 // After successfully queuing packets to the receiver, the client is responsible
17 // for retaining the structure in memory (and unmodified) until all packets have
18 // been received by the handler or the dispatcher shuts down.  There is no way
19 // to cancel a packet which has been queued.
20 //
21 // Multiple packets may be delivered to the same receiver concurrently.
22 //
23 // Concrete implementations: |async::Receiver|, |async::ReceiverMethod|.
24 // Please do not create subclasses of ReceiverBase outside of this library.
25 class ReceiverBase {
26 protected:
27     explicit ReceiverBase(async_receiver_handler_t* handler);
28     ~ReceiverBase();
29 
30     ReceiverBase(const ReceiverBase&) = delete;
31     ReceiverBase(ReceiverBase&&) = delete;
32     ReceiverBase& operator=(const ReceiverBase&) = delete;
33     ReceiverBase& operator=(ReceiverBase&&) = delete;
34 
35 public:
36     // Enqueues a packet of data for delivery to a receiver.
37     //
38     // The |data| will be copied into the packet.  May be NULL to create a
39     // zero-initialized packet payload.
40     //
41     // Returns |ZX_OK| if the packet was successfully enqueued.
42     // Returns |ZX_ERR_BAD_STATE| if the dispatcher is shutting down.
43     // Returns |ZX_ERR_NOT_SUPPORTED| if not supported by the dispatcher.
44     zx_status_t QueuePacket(async_dispatcher_t* dispatcher, const zx_packet_user_t* data = nullptr);
45 
46 protected:
47     template <typename T>
Dispatch(async_receiver_t * receiver)48     static T* Dispatch(async_receiver_t* receiver) {
49         static_assert(offsetof(ReceiverBase, receiver_) == 0, "");
50         auto self = reinterpret_cast<ReceiverBase*>(receiver);
51         return static_cast<T*>(self);
52     }
53 
54 private:
55     async_receiver_t receiver_;
56 };
57 
58 // A receiver whose handler is bound to a |async::Task::Handler| function.
59 //
60 // Prefer using |async::ReceiverMethod| instead for binding to a fixed class member
61 // function since it is more efficient to dispatch.
62 class Receiver final : public ReceiverBase {
63 public:
64     // Handles receipt of packets containing user supplied data.
65     //
66     // The |status| is |ZX_OK| if the packet was successfully delivered and |data|
67     // contains the information from the packet, otherwise |data| is null.
68     using Handler = fbl::Function<void(async_dispatcher_t* dispatcher,
69                                        async::Receiver* receiver,
70                                        zx_status_t status,
71                                        const zx_packet_user_t* data)>;
72 
73     explicit Receiver(Handler handler = nullptr);
74     ~Receiver();
75 
set_handler(Handler handler)76     void set_handler(Handler handler) { handler_ = std::move(handler); }
has_handler()77     bool has_handler() const { return !!handler_; }
78 
79 private:
80     static void CallHandler(async_dispatcher_t* dispatcher, async_receiver_t* receiver,
81                             zx_status_t status, const zx_packet_user_t* data);
82 
83     Handler handler_;
84 };
85 
86 // A receiver whose handler is bound to a fixed class member function.
87 //
88 // Usage:
89 //
90 // class Foo {
91 //     void Handle(async_dispatcher_t* dispatcher, async::ReceiverBase* receiver, zx_status_t status,
92 //                 const zx_packet_user_t* data) { ... }
93 //     async::ReceiverMethod<Foo, &Foo::Handle> receiver_{this};
94 // };
95 template <class Class,
96           void (Class::*method)(async_dispatcher_t* dispatcher, async::ReceiverBase* receiver,
97                                 zx_status_t status, const zx_packet_user_t* data)>
98 class ReceiverMethod final : public ReceiverBase {
99 public:
ReceiverMethod(Class * instance)100     explicit ReceiverMethod(Class* instance)
101         : ReceiverBase(&ReceiverMethod::CallHandler), instance_(instance) {}
102 
103 private:
CallHandler(async_dispatcher_t * dispatcher,async_receiver_t * receiver,zx_status_t status,const zx_packet_user_t * data)104     static void CallHandler(async_dispatcher_t* dispatcher, async_receiver_t* receiver,
105                             zx_status_t status, const zx_packet_user_t* data) {
106         auto self = Dispatch<ReceiverMethod>(receiver);
107         (self->instance_->*method)(dispatcher, self, status, data);
108     }
109 
110     Class* const instance_;
111 };
112 
113 } // namespace async
114