1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#ifndef _THRIFT_TRANSPORT_TVIRTUALTRANSPORT_H_
21#define _THRIFT_TRANSPORT_TVIRTUALTRANSPORT_H_ 1
22
23#include <thrift/transport/TTransport.h>
24
25namespace apache {
26namespace thrift {
27namespace transport {
28
29/**
30 * Helper class that provides default implementations of TTransport methods.
31 *
32 * This class provides default implementations of read(), readAll(), write(),
33 * borrow() and consume().
34 *
35 * In the TTransport base class, each of these methods simply invokes its
36 * virtual counterpart. This class overrides them to always perform the
37 * default behavior, without a virtual function call.
38 *
39 * The primary purpose of this class is to serve as a base class for
40 * TVirtualTransport, and prevent infinite recursion if one of its subclasses
41 * does not override the TTransport implementation of these methods. (Since
42 * TVirtualTransport::read_virt() calls read(), and TTransport::read() calls
43 * read_virt().)
44 */
45class TTransportDefaults : public TTransport {
46public:
47 /*
48 * TTransport *_virt() methods provide reasonable default implementations.
49 * Invoke them non-virtually.
50 */
51 uint32_t read(uint8_t* buf, uint32_t len) { return this->TTransport::read_virt(buf, len); }
52 uint32_t readAll(uint8_t* buf, uint32_t len) { return this->TTransport::readAll_virt(buf, len); }
53 void write(const uint8_t* buf, uint32_t len) { this->TTransport::write_virt(buf, len); }
54 const uint8_t* borrow(uint8_t* buf, uint32_t* len) {
55 return this->TTransport::borrow_virt(buf, len);
56 }
57 void consume(uint32_t len) { this->TTransport::consume_virt(len); }
58
59protected:
60 TTransportDefaults() = default;
61};
62
63/**
64 * Helper class to provide polymorphism for subclasses of TTransport.
65 *
66 * This class implements *_virt() methods of TTransport, to call the
67 * non-virtual versions of these functions in the proper subclass.
68 *
69 * To define your own transport class using TVirtualTransport:
70 * 1) Derive your subclass from TVirtualTransport<your class>
71 * e.g: class MyTransport : public TVirtualTransport<MyTransport> {
72 * 2) Provide your own implementations of read(), readAll(), etc.
73 * These methods should be non-virtual.
74 *
75 * Transport implementations that need to use virtual inheritance when
76 * inheriting from TTransport cannot use TVirtualTransport.
77 *
78 * @author Chad Walters <chad@powerset.com>
79 */
80template <class Transport_, class Super_ = TTransportDefaults>
81class TVirtualTransport : public Super_ {
82public:
83 /*
84 * Implementations of the *_virt() functions, to call the subclass's
85 * non-virtual implementation function.
86 */
87 uint32_t read_virt(uint8_t* buf, uint32_t len) override {
88 return static_cast<Transport_*>(this)->read(buf, len);
89 }
90
91 uint32_t readAll_virt(uint8_t* buf, uint32_t len) override {
92 return static_cast<Transport_*>(this)->readAll(buf, len);
93 }
94
95 void write_virt(const uint8_t* buf, uint32_t len) override {
96 static_cast<Transport_*>(this)->write(buf, len);
97 }
98
99 const uint8_t* borrow_virt(uint8_t* buf, uint32_t* len) override {
100 return static_cast<Transport_*>(this)->borrow(buf, len);
101 }
102
103 void consume_virt(uint32_t len) override { static_cast<Transport_*>(this)->consume(len); }
104
105 /*
106 * Provide a default readAll() implementation that invokes
107 * read() non-virtually.
108 *
109 * Note: subclasses that use TVirtualTransport to derive from another
110 * transport implementation (i.e., not TTransportDefaults) should beware that
111 * this may override any non-default readAll() implementation provided by
112 * the parent transport class. They may need to redefine readAll() to call
113 * the correct parent implementation, if desired.
114 */
115 uint32_t readAll(uint8_t* buf, uint32_t len) {
116 auto* trans = static_cast<Transport_*>(this);
117 return ::apache::thrift::transport::readAll(*trans, buf, len);
118 }
119
120protected:
121 TVirtualTransport() = default;
122
123 /*
124 * Templatized constructors, to allow arguments to be passed to the Super_
125 * constructor. Currently we only support 0, 1, or 2 arguments, but
126 * additional versions can be added as needed.
127 */
128 template <typename Arg_>
129 TVirtualTransport(Arg_ const& arg)
130 : Super_(arg) {}
131
132 template <typename Arg1_, typename Arg2_>
133 TVirtualTransport(Arg1_ const& a1, Arg2_ const& a2)
134 : Super_(a1, a2) {}
135};
136}
137}
138} // apache::thrift::transport
139
140#endif // #ifndef _THRIFT_TRANSPORT_TVIRTUALTRANSPORT_H_
141