49f2517f1eeaedea94fdd9ffb54adfa1f3f744f5
[folly.git] / folly / wangle / channel / HandlerContext-inl.h
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 namespace folly { namespace wangle {
20
21 class PipelineContext {
22  public:
23   virtual ~PipelineContext() {}
24
25   virtual void attachPipeline() = 0;
26   virtual void detachPipeline() = 0;
27
28   virtual void attachTransport() = 0;
29   virtual void detachTransport() = 0;
30
31   template <class H, class HandlerContext>
32   void attachContext(H* handler, HandlerContext* ctx) {
33     if (++handler->attachCount_ == 1) {
34       handler->ctx_ = ctx;
35     } else {
36       handler->ctx_ = nullptr;
37     }
38   }
39
40   virtual void setNextIn(PipelineContext* ctx) = 0;
41   virtual void setNextOut(PipelineContext* ctx) = 0;
42 };
43
44 template <class In>
45 class InboundLink {
46  public:
47   virtual ~InboundLink() {}
48   virtual void read(In msg) = 0;
49   virtual void readEOF() = 0;
50   virtual void readException(exception_wrapper e) = 0;
51 };
52
53 template <class Out>
54 class OutboundLink {
55  public:
56   virtual ~OutboundLink() {}
57   virtual Future<void> write(Out msg) = 0;
58   virtual Future<void> close() = 0;
59 };
60
61 template <class P, class H, class Context>
62 class ContextImplBase : public PipelineContext {
63  public:
64   ~ContextImplBase() {}
65
66   H* getHandler() {
67     return handler_.get();
68   }
69
70   void initialize(P* pipeline, std::shared_ptr<H> handler) {
71     pipeline_ = pipeline;
72     handler_ = std::move(handler);
73   }
74
75   // PipelineContext overrides
76   void attachPipeline() override {
77     if (!attached_) {
78       this->attachContext(handler_.get(), impl_);
79       handler_->attachPipeline(impl_);
80       attached_ = true;
81     }
82   }
83
84   void detachPipeline() override {
85     handler_->detachPipeline(impl_);
86     attached_ = false;
87   }
88
89   void attachTransport() override {
90     DestructorGuard dg(pipeline_);
91     handler_->attachTransport(impl_);
92   }
93
94   void detachTransport() override {
95     DestructorGuard dg(pipeline_);
96     handler_->detachTransport(impl_);
97   }
98
99   void setNextIn(PipelineContext* ctx) override {
100     auto nextIn = dynamic_cast<InboundLink<typename H::rout>*>(ctx);
101     if (nextIn) {
102       nextIn_ = nextIn;
103     } else {
104       throw std::invalid_argument("inbound type mismatch");
105     }
106   }
107
108   void setNextOut(PipelineContext* ctx) override {
109     auto nextOut = dynamic_cast<OutboundLink<typename H::wout>*>(ctx);
110     if (nextOut) {
111       nextOut_ = nextOut;
112     } else {
113       throw std::invalid_argument("outbound type mismatch");
114     }
115   }
116
117  protected:
118   Context* impl_;
119   P* pipeline_;
120   std::shared_ptr<H> handler_;
121   InboundLink<typename H::rout>* nextIn_{nullptr};
122   OutboundLink<typename H::wout>* nextOut_{nullptr};
123
124  private:
125   bool attached_{false};
126   using DestructorGuard = typename P::DestructorGuard;
127 };
128
129 template <class P, class H>
130 class ContextImpl
131   : public HandlerContext<typename H::rout,
132                           typename H::wout>,
133     public InboundLink<typename H::rin>,
134     public OutboundLink<typename H::win>,
135     public ContextImplBase<P, H, HandlerContext<typename H::rout,
136                                                 typename H::wout>> {
137  public:
138   typedef typename H::rin Rin;
139   typedef typename H::rout Rout;
140   typedef typename H::win Win;
141   typedef typename H::wout Wout;
142   static const HandlerDir dir = HandlerDir::BOTH;
143
144   explicit ContextImpl(P* pipeline, std::shared_ptr<H> handler) {
145     this->impl_ = this;
146     this->initialize(pipeline, std::move(handler));
147   }
148
149   // For StaticPipeline
150   ContextImpl() {
151     this->impl_ = this;
152   }
153
154   ~ContextImpl() {}
155
156   // HandlerContext overrides
157   void fireRead(Rout msg) override {
158     DestructorGuard dg(this->pipeline_);
159     if (this->nextIn_) {
160       this->nextIn_->read(std::forward<Rout>(msg));
161     } else {
162       LOG(WARNING) << "read reached end of pipeline";
163     }
164   }
165
166   void fireReadEOF() override {
167     DestructorGuard dg(this->pipeline_);
168     if (this->nextIn_) {
169       this->nextIn_->readEOF();
170     } else {
171       LOG(WARNING) << "readEOF reached end of pipeline";
172     }
173   }
174
175   void fireReadException(exception_wrapper e) override {
176     DestructorGuard dg(this->pipeline_);
177     if (this->nextIn_) {
178       this->nextIn_->readException(std::move(e));
179     } else {
180       LOG(WARNING) << "readException reached end of pipeline";
181     }
182   }
183
184   Future<void> fireWrite(Wout msg) override {
185     DestructorGuard dg(this->pipeline_);
186     if (this->nextOut_) {
187       return this->nextOut_->write(std::forward<Wout>(msg));
188     } else {
189       LOG(WARNING) << "write reached end of pipeline";
190       return makeFuture();
191     }
192   }
193
194   Future<void> fireClose() override {
195     DestructorGuard dg(this->pipeline_);
196     if (this->nextOut_) {
197       return this->nextOut_->close();
198     } else {
199       LOG(WARNING) << "close reached end of pipeline";
200       return makeFuture();
201     }
202   }
203
204   PipelineBase* getPipeline() override {
205     return this->pipeline_;
206   }
207
208   std::shared_ptr<AsyncTransport> getTransport() override {
209     return this->pipeline_->getTransport();
210   }
211
212   void setWriteFlags(WriteFlags flags) override {
213     this->pipeline_->setWriteFlags(flags);
214   }
215
216   WriteFlags getWriteFlags() override {
217     return this->pipeline_->getWriteFlags();
218   }
219
220   void setReadBufferSettings(
221       uint64_t minAvailable,
222       uint64_t allocationSize) override {
223     this->pipeline_->setReadBufferSettings(minAvailable, allocationSize);
224   }
225
226   std::pair<uint64_t, uint64_t> getReadBufferSettings() override {
227     return this->pipeline_->getReadBufferSettings();
228   }
229
230   // InboundLink overrides
231   void read(Rin msg) override {
232     DestructorGuard dg(this->pipeline_);
233     this->handler_->read(this, std::forward<Rin>(msg));
234   }
235
236   void readEOF() override {
237     DestructorGuard dg(this->pipeline_);
238     this->handler_->readEOF(this);
239   }
240
241   void readException(exception_wrapper e) override {
242     DestructorGuard dg(this->pipeline_);
243     this->handler_->readException(this, std::move(e));
244   }
245
246   // OutboundLink overrides
247   Future<void> write(Win msg) override {
248     DestructorGuard dg(this->pipeline_);
249     return this->handler_->write(this, std::forward<Win>(msg));
250   }
251
252   Future<void> close() override {
253     DestructorGuard dg(this->pipeline_);
254     return this->handler_->close(this);
255   }
256
257  private:
258   using DestructorGuard = typename P::DestructorGuard;
259 };
260
261 template <class P, class H>
262 class InboundContextImpl
263   : public InboundHandlerContext<typename H::rout>,
264     public InboundLink<typename H::rin>,
265     public ContextImplBase<P, H, InboundHandlerContext<typename H::rout>> {
266  public:
267   typedef typename H::rin Rin;
268   typedef typename H::rout Rout;
269   typedef typename H::win Win;
270   typedef typename H::wout Wout;
271   static const HandlerDir dir = HandlerDir::IN;
272
273   explicit InboundContextImpl(P* pipeline, std::shared_ptr<H> handler) {
274     this->impl_ = this;
275     this->initialize(pipeline, std::move(handler));
276   }
277
278   // For StaticPipeline
279   InboundContextImpl() {
280     this->impl_ = this;
281   }
282
283   ~InboundContextImpl() {}
284
285   // InboundHandlerContext overrides
286   void fireRead(Rout msg) override {
287     DestructorGuard dg(this->pipeline_);
288     if (this->nextIn_) {
289       this->nextIn_->read(std::forward<Rout>(msg));
290     } else {
291       LOG(WARNING) << "read reached end of pipeline";
292     }
293   }
294
295   void fireReadEOF() override {
296     DestructorGuard dg(this->pipeline_);
297     if (this->nextIn_) {
298       this->nextIn_->readEOF();
299     } else {
300       LOG(WARNING) << "readEOF reached end of pipeline";
301     }
302   }
303
304   void fireReadException(exception_wrapper e) override {
305     DestructorGuard dg(this->pipeline_);
306     if (this->nextIn_) {
307       this->nextIn_->readException(std::move(e));
308     } else {
309       LOG(WARNING) << "readException reached end of pipeline";
310     }
311   }
312
313   PipelineBase* getPipeline() override {
314     return this->pipeline_;
315   }
316
317   std::shared_ptr<AsyncTransport> getTransport() override {
318     return this->pipeline_->getTransport();
319   }
320
321   // InboundLink overrides
322   void read(Rin msg) override {
323     DestructorGuard dg(this->pipeline_);
324     this->handler_->read(this, std::forward<Rin>(msg));
325   }
326
327   void readEOF() override {
328     DestructorGuard dg(this->pipeline_);
329     this->handler_->readEOF(this);
330   }
331
332   void readException(exception_wrapper e) override {
333     DestructorGuard dg(this->pipeline_);
334     this->handler_->readException(this, std::move(e));
335   }
336
337  private:
338   using DestructorGuard = typename P::DestructorGuard;
339 };
340
341 template <class P, class H>
342 class OutboundContextImpl
343   : public OutboundHandlerContext<typename H::wout>,
344     public OutboundLink<typename H::win>,
345     public ContextImplBase<P, H, OutboundHandlerContext<typename H::wout>> {
346  public:
347   typedef typename H::rin Rin;
348   typedef typename H::rout Rout;
349   typedef typename H::win Win;
350   typedef typename H::wout Wout;
351   static const HandlerDir dir = HandlerDir::OUT;
352
353   explicit OutboundContextImpl(P* pipeline, std::shared_ptr<H> handler) {
354     this->impl_ = this;
355     this->initialize(pipeline, std::move(handler));
356   }
357
358   // For StaticPipeline
359   OutboundContextImpl() {
360     this->impl_ = this;
361   }
362
363   ~OutboundContextImpl() {}
364
365   // OutboundHandlerContext overrides
366   Future<void> fireWrite(Wout msg) override {
367     DestructorGuard dg(this->pipeline_);
368     if (this->nextOut_) {
369       return this->nextOut_->write(std::forward<Wout>(msg));
370     } else {
371       LOG(WARNING) << "write reached end of pipeline";
372       return makeFuture();
373     }
374   }
375
376   Future<void> fireClose() override {
377     DestructorGuard dg(this->pipeline_);
378     if (this->nextOut_) {
379       return this->nextOut_->close();
380     } else {
381       LOG(WARNING) << "close reached end of pipeline";
382       return makeFuture();
383     }
384   }
385
386   PipelineBase* getPipeline() override {
387     return this->pipeline_;
388   }
389
390   std::shared_ptr<AsyncTransport> getTransport() override {
391     return this->pipeline_->getTransport();
392   }
393
394   // OutboundLink overrides
395   Future<void> write(Win msg) override {
396     DestructorGuard dg(this->pipeline_);
397     return this->handler_->write(this, std::forward<Win>(msg));
398   }
399
400   Future<void> close() override {
401     DestructorGuard dg(this->pipeline_);
402     return this->handler_->close(this);
403   }
404
405  private:
406   using DestructorGuard = typename P::DestructorGuard;
407 };
408
409 template <class Handler, class Pipeline>
410 struct ContextType {
411   typedef typename std::conditional<
412     Handler::dir == HandlerDir::BOTH,
413     ContextImpl<Pipeline, Handler>,
414     typename std::conditional<
415       Handler::dir == HandlerDir::IN,
416       InboundContextImpl<Pipeline, Handler>,
417       OutboundContextImpl<Pipeline, Handler>
418     >::type>::type
419   type;
420 };
421
422 }} // folly::wangle